193 lines
7.7 KiB
JavaScript
193 lines
7.7 KiB
JavaScript
// Copyright 2020-2023 Nym Technologies SA
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
const RUST_WASM_URL = "zknym_lib_bg.wasm"
|
|
|
|
importScripts('zknym_lib.js');
|
|
|
|
console.log('Initializing worker');
|
|
|
|
// wasm_bindgen creates a global variable (with the exports attached) that is in scope after `importScripts`
|
|
const {
|
|
set_panic_hook,
|
|
prepareBlindSign,
|
|
blindSign,
|
|
setup,
|
|
signSimple,
|
|
verifySimple,
|
|
keygen,
|
|
simpleRandomiseCredential,
|
|
ttpKeygen,
|
|
aggregateVerificationKeyShares,
|
|
aggregateSignatureShares,
|
|
proveBandwidthCredential,
|
|
verifyCredential,
|
|
NymIssuanceBandwidthVoucher
|
|
} = wasm_bindgen;
|
|
|
|
|
|
// I've made it before starting on VPN API so didn't know exact requirements
|
|
function simpleGenericUsage() {
|
|
// SIMPLE SETUP: no threshold, no private attributes
|
|
console.log(">>> simple example...")
|
|
setup({numAttributes: 4, setGlobal: true})
|
|
let keypair = keygen()
|
|
|
|
let vk = keypair.verificationKey();
|
|
|
|
let goodAttributes = ["foomp", "foo", "bar"]
|
|
let badAttributes = ["I", "didn't", "sign", "that"]
|
|
|
|
let sig_simple = signSimple(goodAttributes, keypair)
|
|
console.log("signature:", sig_simple.stringify());
|
|
|
|
let verified = verifySimple(vk, goodAttributes, sig_simple)
|
|
let verified2 = verifySimple(vk, badAttributes, sig_simple)
|
|
|
|
let randomised = simpleRandomiseCredential(sig_simple);
|
|
let verified3 = verifySimple(vk, goodAttributes, randomised)
|
|
|
|
console.log(`verified1: ${verified} (good attributes), verified2: ${verified2} (bad attributes), verified3: ${verified3} (good attributes + randomised)`)
|
|
|
|
|
|
// 'NORMAL' SETUP: threshold with private attributes:
|
|
console.log(">>> full example...")
|
|
let t3_5_keys = ttpKeygen({threshold: 3, authorities: 5})
|
|
|
|
// currently they HAVE TO correspond to our bandwidth credential attributes,
|
|
// i.e. serial number and binding number, because it seems we removed generic verification methods
|
|
// ¯\_(ツ)_/¯
|
|
let serialNumber = "credential-serial-number"
|
|
let bindingNumber = "credential-binding-number"
|
|
let privateAttributes = [serialNumber, bindingNumber]
|
|
let publicAttributes = ["foo", "bar"]
|
|
|
|
// sign the attributes
|
|
console.log("creating partial credentials...");
|
|
let blindSignRequestData = prepareBlindSign(privateAttributes, publicAttributes)
|
|
let blindSignRequest = blindSignRequestData.blindSignRequest()
|
|
let blindPartial1 = blindSign(t3_5_keys[0], blindSignRequest, publicAttributes)
|
|
let blindPartial2 = blindSign(t3_5_keys[1], blindSignRequest, publicAttributes)
|
|
let blindPartial3 = blindSign(t3_5_keys[2], blindSignRequest, publicAttributes)
|
|
let blindPartial4 = blindSign(t3_5_keys[3], blindSignRequest, publicAttributes)
|
|
let blindPartial5 = blindSign(t3_5_keys[4], blindSignRequest, publicAttributes)
|
|
|
|
console.log("unblinding signatures...");
|
|
let pedersenOpenings = blindSignRequestData.pedersenCommitmentsOpenings()
|
|
let partialSig1 = blindPartial1.unblind(t3_5_keys[0].verificationKey(), pedersenOpenings)
|
|
let partialSig2 = blindPartial2.unblind(t3_5_keys[1].verificationKey(), pedersenOpenings)
|
|
let partialSig3 = blindPartial3.unblind(t3_5_keys[2].verificationKey(), pedersenOpenings)
|
|
let partialSig4 = blindPartial4.unblind(t3_5_keys[3].verificationKey(), pedersenOpenings)
|
|
let partialSig5 = blindPartial5.unblind(t3_5_keys[4].verificationKey(), pedersenOpenings)
|
|
|
|
// aggregate signature:
|
|
console.log("aggregating signatures...")
|
|
let sigShare1 = partialSig1.intoShare(t3_5_keys[0].index())
|
|
let sigShare2 = partialSig2.intoShare(t3_5_keys[1].index())
|
|
let sigShare3 = partialSig3.intoShare(t3_5_keys[2].index())
|
|
let sigShare4 = partialSig4.intoShare(t3_5_keys[3].index())
|
|
let sigShare5 = partialSig5.intoShare(t3_5_keys[4].index())
|
|
let masterCred1 = aggregateSignatureShares([sigShare1.cloneDataPointer(), sigShare3, sigShare4])
|
|
let masterCred2 = aggregateSignatureShares([sigShare1, sigShare2, sigShare5])
|
|
|
|
// key shares:
|
|
console.log("aggregating verification keys...");
|
|
let vk1 = t3_5_keys[0].verificationKeyShare()
|
|
let vk2 = t3_5_keys[1].verificationKeyShare()
|
|
let vk3 = t3_5_keys[2].verificationKeyShare()
|
|
let vk4 = t3_5_keys[3].verificationKeyShare()
|
|
let vk5 = t3_5_keys[4].verificationKeyShare()
|
|
|
|
// master verification key:
|
|
let masterVk1 = aggregateVerificationKeyShares([vk1, vk2.cloneDataPointer(), vk3])
|
|
let masterVk2 = aggregateVerificationKeyShares([vk2, vk4, vk5])
|
|
|
|
// attempt to 'spend'/'prove' the credential (note that the master keys and credentials should be cryptographically identical):
|
|
console.log("attempting to spend the credential...");
|
|
let verifyReq1 = proveBandwidthCredential(masterVk1, masterCred2, serialNumber, bindingNumber)
|
|
let verifyReq2 = proveBandwidthCredential(masterVk2, masterCred1, serialNumber, bindingNumber)
|
|
|
|
console.log("verifying the credential...");
|
|
let verifiedMaster1 = verifyCredential(masterVk1, verifyReq1, publicAttributes)
|
|
let verifiedMaster2 = verifyCredential(masterVk1, verifyReq2, publicAttributes)
|
|
|
|
console.log(`verified1: ${verifiedMaster1}, verified2: ${verifiedMaster2}`)
|
|
}
|
|
|
|
async function frontendSimulation() {
|
|
console.log("getting opts");
|
|
const res = await fetch("http://localhost:8080/api/v1/bandwidth-voucher/prehashed-public-attributes", {
|
|
headers: new Headers({'Authorization': 'Bearer foomp'})
|
|
});
|
|
const opts = await res.json()
|
|
|
|
const issuanceVoucher = new NymIssuanceBandwidthVoucher(opts)
|
|
const blindSignRequest = issuanceVoucher.getBlindSignRequest()
|
|
|
|
console.log("getting partial vks");
|
|
const partialVksRes = await fetch("http://localhost:8080/api/v1/bandwidth-voucher/partial-verification-keys", {
|
|
headers: new Headers({'Authorization': 'Bearer foomp'})
|
|
});
|
|
const partialVks = await partialVksRes.json()
|
|
|
|
console.log("getting master vk")
|
|
const masterVkRes = await fetch("http://localhost:8080/api/v1/bandwidth-voucher/master-verification-key", {
|
|
headers: new Headers({'Authorization': 'Bearer foomp'})
|
|
});
|
|
const masterVk = await masterVkRes.json()
|
|
|
|
console.log("getting blinded shares")
|
|
const sharesRes = await fetch("http://localhost:8080/api/v1/bandwidth-voucher/obtain", {
|
|
method: "POST",
|
|
headers: new Headers(
|
|
{
|
|
'Authorization': 'Bearer foomp',
|
|
"Content-Type": "application/json",
|
|
}
|
|
),
|
|
body: JSON.stringify({
|
|
blindSignRequest
|
|
})
|
|
});
|
|
|
|
const credentialShares = await sharesRes.json()
|
|
|
|
console.log("unblinding shares");
|
|
const bandwidthVoucher = issuanceVoucher.unblindShares(credentialShares, partialVks)
|
|
console.log("is valid: ", bandwidthVoucher.ensureIsValid(masterVk.bs58EncodedKey))
|
|
|
|
const serialised = bandwidthVoucher.serialise();
|
|
console.log("serialised:\n", serialised)
|
|
}
|
|
|
|
async function main() {
|
|
console.log(">>>>>>>>>>>>>>>>>>>>> JS WORKER MAIN START");
|
|
|
|
// load rust WASM package
|
|
await wasm_bindgen(RUST_WASM_URL);
|
|
console.log('Loaded RUST WASM');
|
|
|
|
// sets up better stack traces in case of in-rust panics
|
|
set_panic_hook();
|
|
|
|
|
|
await frontendSimulation()
|
|
|
|
|
|
console.log(">>>>>>>>>>>>>>>>>>>>> JS WORKER MAIN END")
|
|
}
|
|
|
|
|
|
// Let's get started!
|
|
main(); |