An implementation of BBS, BBS+ signatures, PS signatures, bilinear map accumulators, verifiable encryption, range proof and composite proof using rust compiled to wasm. This project started as fork of @mattrglobal/bbs-signatures
npm install @docknetwork/crypto-wasmThis repository is a WASM wrapper over Dock's Rust crypto library and is home to
- BBS+, a performant multi-message digital signature algorithm implementation which supports
deriving zero knowledge proofs that enable selective disclosure from the originally signed message set.
- bilinear map, positive and universal accumulators supporting single and batch updates to the accumulator and witness
- composite proof system that lets you combine BBS+ signatures, accumulators and Schnorr protocols
This project started as fork of @mattrglobal/bbs-signatures but now only borrows the
WASM setup; the API is quite different.
This repo contains a thin wrapper over the Rust code and exposes free floating JS functions. For a Typescript wrapper with better
abstractions, check this.
min and max, i.e. min <= message <= max without To use this package within your project simply run
```
npm install @docknetwork/crypto-wasm
Or with Yarn
``
yarn add @docknetwork/crypto-wasm
See the sample directory for a runnable demo's.
The following is a short sample on how to use the API
Within a digital signature there are several elements for which it is useful to know the size, the following table
outlines the general equation for calculating element sizes in relation to BBS+ signatures as it is dependent on the
pairing friendly curve used.
| Element | Size Equation |
| ----------- | ------------------------------------ |
| Private Key | F |
| Public Key | G2 |
| Signature | G1 + 2\*F |
| Proof | 5G1 + (4 + no_of_hidden_messages)F |
- F A field elementG1
- A point in the field of G1G2
- A point in the field of G2no_of_hidden_messages
- The number of the hidden messages
This library includes specific support for BLS12-381 keys with BBS+ signatures and hence gives rise to the following
concrete sizes
| Element | Size with BLS12-381 |
| ----------- | --------------------------------------- |
| Private Key | 32 Bytes |
| Public Key | 96 Bytes |
| Signature | 112 Bytes |
| Proof | 368 + (no_of_hidden_messages)\*32 Bytes |
The following describes how to get started as a contributor to this project
The following is a list of dependencies you must install to build and contribute to this project
- Yarn - make sure you're not using the legacy version.
- Rust
For more details see our contribution guidelines
#### Install
To install the package dependencies run:
``
yarn install --frozen-lockfile
#### Build
To build the project for debug, run:
``
yarn build
To build the project for release, run:
``
yarn build:release
To build the project for profiling (slower to build, faster to run), run:
``
yarn build:profiling
#### Test
To run the all test in the project run:
``
yarn test
To run just the tests for a node environment using the wasm module run:
``
yarn test:wasm
Before running the JS tests, build the project with yarn build.
To run just the tests for a browser environment run:
``
yarn test:browser
Above runs the Rust tests here. To run specific modules, use following wasm-pack command and pass the test module
name. Eg. for running accumulator tests, run:
``
wasm-pack test --headless --chrome -- --test accumulator
For BBS+, run:
``
wasm-pack test --headless --chrome -- --test bbs_plus
For accumulator, run:
``
wasm-pack test --headless --chrome -- --test accumulator
Some tests take long (few minutes) to run and to prevent timeout of such tests, set env variable WASM_BINDGEN_TEST_TIMEOUT
to the number of seconds for the timeout. eg. the following sets the timeout to 360 seconds, i.e. 6 minutes
``
WASM_BINDGEN_TEST_TIMEOUT=360 wasm-pack test --headless --chrome
It's better to run tests in release mode since debug mode takes a long time. Increasing the timeout helps as well as shown below.
``
WASM_BINDGEN_TEST_TIMEOUT=360 wasm-pack test --release --headless --chrome
#### Benchmark
To benchmark the implementation locally in a node environment using the wasm module run:
``
yarn benchmark:wasm
Since loading WASM is an async process, before any function can be used initializeWasm should be called and resolved which
loads WASM.
Example of using BBS+ signature
`js
import {
bbsPlusGenerateSignatureParamsG1, bbsPlusGeneratePublicKeyG2, bbsPlusGenerateSigningKey, bbsPlusSignG1, bbsPlusVerifyG1,
bbsPlusInitializeProofOfKnowledgeOfSignature, bbsPlusGenProofOfKnowledgeOfSignature, bbsPlusVerifyProofOfKnowledgeOfSignature,
bbsPlusChallengeContributionFromProtocol, bbsPlusChallengeContributionFromProof, generateChallengeFromBytes,
initializeWasm
} from "../../../lib";
const stringToBytes = (str: string) => Uint8Array.from(Buffer.from(str, "utf-8"));
const main = async () => {
// Load the WASM module
await initializeWasm();
// Generate some random messages
const messages = [
Uint8Array.from(Buffer.from("message1", "utf8")),
Uint8Array.from(Buffer.from("message2", "utf8")),
Uint8Array.from(Buffer.from("message3", "utf8")),
];
const label = stringToBytes("test-params");
const messageCount = messages.length;
// Generate params deterministically using a label
const sigParams = bbsPlusGenerateSignatureParamsG1(messageCount, label);
console.log('params is', sigParams);
// Generate a new key pair
const sk = bbsPlusGenerateSigningKey();
const pk = bbsPlusGeneratePublicKeyG2(sk, sigParams);
console.log("Key pair generated");
console.log(
Public key base64 = ${Buffer.from(pk).toString("base64")}
);
console.log("Signing a message set of " + messages);
// Create the signature
const signature = bbsPlusSignG1(messages, sk, sigParams, true);
console.log(
Output signature base64 = ${Buffer.from(signature).toString("base64")}
);
// Verify the signature
const isVerified = bbsPlusVerifyG1(messages, signature, pk, sigParams, true);
const isVerifiedString = JSON.stringify(isVerified);
console.log(Signature verified ? ${isVerifiedString});
// Derive a proof from the signature revealing the first message
const revealed = new Set
revealed.add(0);
const revealedMsgs = new Map();
revealedMsgs.set(0, messages[0]);
const protocol = bbsPlusInitializeProofOfKnowledgeOfSignature(
signature,
sigParams,
messages,
new Map(),
revealed,
true
);
const challengeProver = generateChallengeFromBytes(bbsPlusChallengeContributionFromProtocol(protocol, revealedMsgs, sigParams, true));
const proof = bbsPlusGenProofOfKnowledgeOfSignature(protocol, challengeProver);
console.log(Output proof base64 = ${Buffer.from(proof).toString("base64")});
// Verify the created proof
const challengeVerifier = generateChallengeFromBytes(bbsPlusChallengeContributionFromProof(proof, revealedMsgs, sigParams, true));
const isProofVerified = bbsPlusVerifyProofOfKnowledgeOfSignature(
proof,
revealedMsgs,
challengeVerifier,
pk,
sigParams,
true,
);
const isProofVerifiedString = JSON.stringify(isProofVerified);
console.log(Proof verified ? ${isProofVerifiedString});
};
main();
`
See the tests for more thorough examples.
This library uses the creates defined in Dock's crypto library which is then
wrapped and exposed in javascript/typescript using Web Assembly.
Please see our security policy for additional details about responsible disclosure of security related issues.
For those interested in more details, you might find the following resources helpful
- BLS12-381 For The Rest Of Us
- Pairing-based cryptography
- Exploring Elliptic Curve Pairings
- Anonymous Attestation Using the Strong Diffie Hellman Assumption Revisited
- Pairing Friendly Curves
- BBS+ signature defined in Anonymous Attestation Using the Strong Diffie Hellman Assumption Revisited
- Dynamic accumulator defined in Dynamic Universal Accumulator with Batch Update over Bilinear Groups
- Verifiable encryption using SAVER
- LegoGroth16, described in the appending H.5 of the Legosnark paper
To build, use
``
BUILD_MODE=DEBUG ./scripts/build-package.sh
or
``
BUILD_MODE=RELEASE ./scripts/build-package.sh
or
``
BUILD_MODE=PROFILING ./scripts/build-package.sh
To run jest tests, build with target nodejs as wasm-pack build --out-dir lib --target nodejs`