Compare commits

...

2 Commits

10 changed files with 5342 additions and 2400 deletions

1
.npmignore Normal file

@ -0,0 +1 @@
test

1
.npmrc Normal file

@ -0,0 +1 @@
@tornado:registry=https://git.tornado.ws/api/packages/tornado-packages/npm/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

467
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,40 +1,40 @@
{ {
"name": "websnark", "name": "@tornado/websnark",
"version": "0.0.4", "version": "0.0.4",
"description": "big integer library to work in Zq", "description": "big integer library to work in Zq",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"test": "mocha --experimental-worker", "test": "mocha --experimental-worker",
"buildwasm": "node tools/buildwasm.js", "buildwasm": "node tools/buildwasm.js",
"build": "node tools/buildwasm.js; browserify main.js -o build/websnark.js --exclude worker_threads --exclude crypto; cp build/websnark.js example/websnark.js" "build": "node tools/buildwasm.js && browserify main.js -o build/websnark.js --exclude worker_threads --exclude crypto && cp build/websnark.js example/websnark.js"
}, },
"keywords": [ "keywords": [
"bigint", "bigint",
"bignum", "bignum",
"biginteger", "biginteger",
"zq", "zq",
"elliptic", "elliptic",
"curve", "curve",
"prime", "prime",
"field" "field"
], ],
"author": "Jordi Baylina", "author": "Jordi Baylina",
"license": "GPL-3.0", "license": "GPL-3.0",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/iden3/websnark.git" "url": "https://git.tornado.ws/tornado-packages/websnark"
}, },
"devDependencies": { "devDependencies": {
"browserify": "^16.2.3", "browserify": "^16.2.3",
"eslint": "^5.14.0", "eslint": "^5.14.0",
"eslint-plugin-mocha": "^5.3.0", "eslint-plugin-mocha": "^5.3.0",
"eslint-plugin-webassembly": "^1.8.4", "eslint-plugin-webassembly": "^1.8.4",
"mocha": "^6.1.4", "mocha": "^6.1.4",
"package": "^1.0.1", "package": "^1.0.1",
"snarkjs": "git+https://development.tornadocash.community/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5", "wasmbuilder": "0.0.3"
"wasmbuilder": "0.0.3" },
}, "dependencies": {
"dependencies": { "@tornado/snarkjs": "^0.1.20",
"big-integer": "1.6.42" "big-integer": "1.6.42"
} }
} }

@ -18,20 +18,20 @@
*/ */
const bigInt = require("big-integer"); const bigInt = require("big-integer");
const Circuit = require("snarkjs/src/circuit"); const Circuit = require("@tornado/snarkjs/src/circuit");
const bigInt2 = require("snarkjs/src/bigint"); const bigInt2 = require("@tornado/snarkjs/src/bigint");
const hexifyBigInts = require("../tools/stringifybigint").hexifyBigInts; const hexifyBigInts = require("../tools/stringifybigint").hexifyBigInts;
const unhexifyBigInts = require("../tools/stringifybigint").unhexifyBigInts; const unhexifyBigInts = require("../tools/stringifybigint").unhexifyBigInts;
const stringifyBigInts = require("../tools/stringifybigint").stringifyBigInts; const stringifyBigInts = require("../tools/stringifybigint").stringifyBigInts;
const unstringifyBigInts = require("../tools/stringifybigint").unstringifyBigInts; const unstringifyBigInts = require("../tools/stringifybigint").unstringifyBigInts;
const stringifyBigInts2 = require("snarkjs/src/stringifybigint").stringifyBigInts; const stringifyBigInts2 = require("@tornado/snarkjs/src/stringifybigint").stringifyBigInts;
const unstringifyBigInts2 = require("snarkjs/src/stringifybigint").unstringifyBigInts; const unstringifyBigInts2 = require("@tornado/snarkjs/src/stringifybigint").unstringifyBigInts;
function bigInt2BytesLE(_a, len) { function bigInt2BytesLE(_a, len) {
const b = Array(len); const b = Array(len);
let v = bigInt(_a); let v = bigInt(_a);
for (let i=0; i<len; i++) { for (let i = 0; i < len; i++) {
b[i] = v.and(0xFF).toJSNumber(); b[i] = v.and(0xff).toJSNumber();
v = v.shiftRight(8); v = v.shiftRight(8);
} }
return b; return b;
@ -40,8 +40,8 @@ function bigInt2BytesLE(_a, len) {
function bigInt2U32LE(_a, len) { function bigInt2U32LE(_a, len) {
const b = Array(len); const b = Array(len);
let v = bigInt(_a); let v = bigInt(_a);
for (let i=0; i<len; i++) { for (let i = 0; i < len; i++) {
b[i] = v.and(0xFFFFFFFF).toJSNumber(); b[i] = v.and(0xffffffff).toJSNumber();
v = v.shiftRight(32); v = v.shiftRight(32);
} }
return b; return b;
@ -52,9 +52,9 @@ function convertWitness(witness) {
const buff = new ArrayBuffer(buffLen); const buff = new ArrayBuffer(buffLen);
const h = { const h = {
dataView: new DataView(buff), dataView: new DataView(buff),
offset: 0 offset: 0,
}; };
const mask = bigInt2(0xFFFFFFFF); const mask = bigInt2(0xffffffff);
for (let i = 0; i < witness.length; i++) { for (let i = 0; i < witness.length; i++) {
for (let j = 0; j < 8; j++) { for (let j = 0; j < 8; j++) {
const v = Number(witness[i].shr(j * 32).and(mask)); const v = Number(witness[i].shr(j * 32).and(mask));
@ -73,13 +73,17 @@ function toHex32(number) {
function toSolidityInput(proof) { function toSolidityInput(proof) {
const flatProof = unstringifyBigInts([ const flatProof = unstringifyBigInts([
proof.pi_a[0], proof.pi_a[1], proof.pi_a[0],
proof.pi_b[0][1], proof.pi_b[0][0], proof.pi_a[1],
proof.pi_b[1][1], proof.pi_b[1][0], proof.pi_b[0][1],
proof.pi_c[0], proof.pi_c[1], proof.pi_b[0][0],
proof.pi_b[1][1],
proof.pi_b[1][0],
proof.pi_c[0],
proof.pi_c[1],
]); ]);
const result = { const result = {
proof: "0x" + flatProof.map(x => toHex32(x)).join("") proof: "0x" + flatProof.map((x) => toHex32(x)).join(""),
}; };
if (proof.publicSignals) { if (proof.publicSignals) {
result.publicSignals = hexifyBigInts(unstringifyBigInts(proof.publicSignals)); result.publicSignals = hexifyBigInts(unstringifyBigInts(proof.publicSignals));
@ -87,11 +91,11 @@ function toSolidityInput(proof) {
return result; return result;
} }
function genWitness(input, circuitJson) { function genWitness(input, circuitJson) {
const circuit = new Circuit(unstringifyBigInts2(circuitJson)); const circuit = new Circuit(unstringifyBigInts2(circuitJson));
const witness = circuit.calculateWitness(unstringifyBigInts2(input)); const witness = circuit.calculateWitness(unstringifyBigInts2(input));
const publicSignals = witness.slice(1, circuit.nPubInputs + circuit.nOutputs + 1); const publicSignals = witness.slice(1, circuit.nPubInputs + circuit.nOutputs + 1);
return {witness, publicSignals}; return { witness, publicSignals };
} }
async function genWitnessAndProve(groth16, input, circuitJson, provingKey) { async function genWitnessAndProve(groth16, input, circuitJson, provingKey) {
@ -102,4 +106,4 @@ async function genWitnessAndProve(groth16, input, circuitJson, provingKey) {
return result; return result;
} }
module.exports = {bigInt2BytesLE, bigInt2U32LE, toSolidityInput, genWitnessAndProve}; module.exports = { bigInt2BytesLE, bigInt2U32LE, toSolidityInput, genWitnessAndProve };

@ -1,6 +1,6 @@
const assert = require("assert"); const assert = require("assert");
const refBn128 = require("snarkjs").bn128; const refBn128 = require("@tornado/snarkjs").bn128;
const refBigInt = require("snarkjs").bigInt; const refBigInt = require("@tornado/snarkjs").bigInt;
const buildBn128 = require("../index.js").buildBn128; const buildBn128 = require("../index.js").buildBn128;
@ -15,7 +15,7 @@ describe("Basic tests for g1 in bn128", () => {
bn128.g1_fromMontgomery(p1, p1); bn128.g1_fromMontgomery(p1, p1);
const d = bn128.g1_getPoint(p1); const d = bn128.g1_getPoint(p1);
for (let i=0; i<3; i++) { for (let i = 0; i < 3; i++) {
d[i] = refBigInt(d[i].toString()); d[i] = refBigInt(d[i].toString());
} }
@ -39,7 +39,6 @@ describe("Basic tests for g1 in bn128", () => {
d[1] = refBigInt(d[1].toString()); d[1] = refBigInt(d[1].toString());
d[2] = refBigInt(d[2].toString()); d[2] = refBigInt(d[2].toString());
assert(d[0].equals(refD[0])); assert(d[0].equals(refD[0]));
assert(d[1].equals(refD[1])); assert(d[1].equals(refD[1]));
assert(d[2].equals(1)); assert(d[2].equals(1));
@ -59,7 +58,7 @@ describe("Basic tests for g1 in bn128", () => {
bn128.g1_fromMontgomery(p1, p1); bn128.g1_fromMontgomery(p1, p1);
const d = bn128.g1_getPoint(p1); const d = bn128.g1_getPoint(p1);
for (let i=0; i<3; i++) { for (let i = 0; i < 3; i++) {
d[i] = refBigInt(d[i].toString()); d[i] = refBigInt(d[i].toString());
} }
@ -96,12 +95,11 @@ describe("Basic tests for g1 in bn128", () => {
bn128.g1_fromMontgomery(p2, p2); bn128.g1_fromMontgomery(p2, p2);
const d = bn128.g1_getPoint(p2); const d = bn128.g1_getPoint(p2);
for (let i=0; i<3; i++) { for (let i = 0; i < 3; i++) {
d[i] = refBigInt(d[i].toString()); d[i] = refBigInt(d[i].toString());
} }
assert(refBn128.G1.equals(d, refD)); assert(refBn128.G1.equals(d, refD));
}).timeout(10000000); }).timeout(10000000);
it("It should do a basic point doubling in G2", async () => { it("It should do a basic point doubling in G2", async () => {
const bn128 = await buildBn128(); const bn128 = await buildBn128();
@ -113,8 +111,8 @@ describe("Basic tests for g1 in bn128", () => {
bn128.g2_fromMontgomery(p1, p1); bn128.g2_fromMontgomery(p1, p1);
const d = bn128.g2_getPoint(p1); const d = bn128.g2_getPoint(p1);
for (let i=0; i<3; i++) { for (let i = 0; i < 3; i++) {
for (let j=0; j<2; j++) { for (let j = 0; j < 2; j++) {
d[i][j] = refBigInt(d[i][j].toString()); d[i][j] = refBigInt(d[i][j].toString());
} }
} }
@ -135,8 +133,8 @@ describe("Basic tests for g1 in bn128", () => {
bn128.g2_fromMontgomery(p2, p2); bn128.g2_fromMontgomery(p2, p2);
const d = bn128.g2_getPoint(p2); const d = bn128.g2_getPoint(p2);
for (let i=0; i<3; i++) { for (let i = 0; i < 3; i++) {
for (let j=0; j<2; j++) { for (let j = 0; j < 2; j++) {
d[i][j] = refBigInt(d[i][j].toString()); d[i][j] = refBigInt(d[i][j].toString());
assert(d[i][j].equals(refD[i][j])); assert(d[i][j].equals(refD[i][j]));
} }

@ -1,6 +1,6 @@
const assert = require("assert"); const assert = require("assert");
const refBn128 = require("snarkjs").bn128; const refBn128 = require("@tornado/snarkjs").bn128;
const refBigInt = require("snarkjs").bigInt; const refBigInt = require("@tornado/snarkjs").bigInt;
const buildBn128 = require("../index.js").buildBn128; const buildBn128 = require("../index.js").buildBn128;
@ -8,11 +8,11 @@ describe("FFT tests", () => {
it("create a basic FFT", async () => { it("create a basic FFT", async () => {
const bn128 = await buildBn128(); const bn128 = await buildBn128();
const N=4; const N = 4;
const p = bn128.alloc(32*N); const p = bn128.alloc(32 * N);
for (let i=0; i<N; i++) { for (let i = 0; i < N; i++) {
bn128.putInt(p+i*32, i); bn128.putInt(p + i * 32, i);
} }
bn128.fft_toMontgomeryN(p, p, N); bn128.fft_toMontgomeryN(p, p, N);
@ -20,20 +20,20 @@ describe("FFT tests", () => {
bn128.fft_ifft(p, N); bn128.fft_ifft(p, N);
bn128.fft_fromMontgomeryN(p, p, N); bn128.fft_fromMontgomeryN(p, p, N);
for (let i=0; i<N; i++) { for (let i = 0; i < N; i++) {
const a = bn128.getInt(p+i*32); const a = bn128.getInt(p + i * 32);
assert.equal(a,i); assert.equal(a, i);
} }
}); });
it("create a do it reverselly FFT", async () => { it("create a do it reverselly FFT", async () => {
const bn128 = await buildBn128(); const bn128 = await buildBn128();
const N=1024; const N = 1024;
const p = bn128.alloc(32*N); const p = bn128.alloc(32 * N);
for (let i=0; i<N; i++) { for (let i = 0; i < N; i++) {
bn128.putInt(p+i*32, i); bn128.putInt(p + i * 32, i);
} }
bn128.fft_toMontgomeryN(p, p, N); bn128.fft_toMontgomeryN(p, p, N);
@ -41,19 +41,19 @@ describe("FFT tests", () => {
bn128.fft_fft(p, N, 0); bn128.fft_fft(p, N, 0);
bn128.fft_fromMontgomeryN(p, p, N); bn128.fft_fromMontgomeryN(p, p, N);
for (let i=0; i<N; i++) { for (let i = 0; i < N; i++) {
const a = bn128.getInt(p+i*32); const a = bn128.getInt(p + i * 32);
assert.equal(a,i); assert.equal(a, i);
} }
}); });
it("test with zeros", async () => { it("test with zeros", async () => {
const bn128 = await buildBn128(); const bn128 = await buildBn128();
const N=1024; const N = 1024;
const p = bn128.alloc(32*N); const p = bn128.alloc(32 * N);
for (let i=0; i<N; i++) { for (let i = 0; i < N; i++) {
bn128.putInt(p+i*32, (i%2 == 0)? 0 : 1); bn128.putInt(p + i * 32, i % 2 == 0 ? 0 : 1);
} }
bn128.fft_toMontgomeryN(p, p, N); bn128.fft_toMontgomeryN(p, p, N);
@ -61,63 +61,61 @@ describe("FFT tests", () => {
bn128.fft_fft(p, N, 0); bn128.fft_fft(p, N, 0);
bn128.fft_fromMontgomeryN(p, p, N); bn128.fft_fromMontgomeryN(p, p, N);
for (let i=0; i<N; i++) { for (let i = 0; i < N; i++) {
const a = bn128.getInt(p+i*32); const a = bn128.getInt(p + i * 32);
assert.equal(a,(i%2 == 0)? 0 : 1); assert.equal(a, i % 2 == 0 ? 0 : 1);
} }
}); });
it("test interleaved", async () => { it("test interleaved", async () => {
const bn128 = await buildBn128(); const bn128 = await buildBn128();
const N=1024; const N = 1024;
const p = bn128.alloc(32*N); const p = bn128.alloc(32 * N);
const pr1 = bn128.alloc(32*N*2); const pr1 = bn128.alloc(32 * N * 2);
const pr2 = bn128.alloc(32*N*2); const pr2 = bn128.alloc(32 * N * 2);
for (let i=0; i<N; i++) { for (let i = 0; i < N; i++) {
bn128.putInt(p+i*32, i); bn128.putInt(p + i * 32, i);
} }
bn128.fft_toMontgomeryN(p, p, N); bn128.fft_toMontgomeryN(p, p, N);
bn128.fft_fft(p, N, 0); bn128.fft_fft(p, N, 0);
bn128.fft_copyNInterleaved(p, pr1, N); bn128.fft_copyNInterleaved(p, pr1, N);
for (let i=0; i<N; i++) { for (let i = 0; i < N; i++) {
bn128.putInt(p+i*32, i); bn128.putInt(p + i * 32, i);
} }
bn128.fft_toMontgomeryN(p, p, N); bn128.fft_toMontgomeryN(p, p, N);
bn128.fft_fft(p, N, 1); bn128.fft_fft(p, N, 1);
bn128.fft_copyNInterleaved(p, pr1+32, N); bn128.fft_copyNInterleaved(p, pr1 + 32, N);
bn128.fft_fromMontgomeryN(pr1, pr1, N*2); bn128.fft_fromMontgomeryN(pr1, pr1, N * 2);
for (let i=0; i<N; i++) { for (let i = 0; i < N; i++) {
bn128.putInt(pr2+i*32, i); bn128.putInt(pr2 + i * 32, i);
} }
for (let i=N; i<N*2; i++) { for (let i = N; i < N * 2; i++) {
bn128.putInt(pr2+i*32, 0); bn128.putInt(pr2 + i * 32, 0);
} }
bn128.fft_toMontgomeryN(pr2, pr2, N*2); bn128.fft_toMontgomeryN(pr2, pr2, N * 2);
bn128.fft_fft(pr2, N*2, 0); bn128.fft_fft(pr2, N * 2, 0);
bn128.fft_fromMontgomeryN(pr2, pr2, N*2); bn128.fft_fromMontgomeryN(pr2, pr2, N * 2);
for (let i=0; i<N*2; i++) { for (let i = 0; i < N * 2; i++) {
const a = bn128.getInt(pr1+i*32, 1); const a = bn128.getInt(pr1 + i * 32, 1);
const b = bn128.getInt(pr2+i*32, 1); const b = bn128.getInt(pr2 + i * 32, 1);
assert(a.equals(b)); assert(a.equals(b));
} }
bn128.fft_toMontgomeryN(pr1, pr1, N*2); bn128.fft_toMontgomeryN(pr1, pr1, N * 2);
bn128.fft_ifft(pr1, N*2, 0); bn128.fft_ifft(pr1, N * 2, 0);
bn128.fft_fromMontgomeryN(pr1, pr1, N*2); bn128.fft_fromMontgomeryN(pr1, pr1, N * 2);
for (let i=0; i<N; i++) { for (let i = 0; i < N; i++) {
const a = bn128.getInt(pr1+i*32, 1); const a = bn128.getInt(pr1 + i * 32, 1);
assert.equal(a,i); assert.equal(a, i);
} }
for (let i=N; i<N*2; i++) { for (let i = N; i < N * 2; i++) {
const a = bn128.getInt(pr1+i*32, 1); const a = bn128.getInt(pr1 + i * 32, 1);
assert.equal(a,0); assert.equal(a, 0);
} }
}); });
}); });

@ -1,8 +1,7 @@
const assert = require("assert"); const assert = require("assert");
const fs = require("fs"); const fs = require("fs");
const path = require("path"); const path = require("path");
const snarkjs = require("snarkjs"); const snarkjs = require("@tornado/snarkjs");
const buildGroth16 = require("../index.js").buildGroth16; const buildGroth16 = require("../index.js").buildGroth16;
@ -18,8 +17,8 @@ describe("Basic tests for groth16 proof generator", () => {
const pkey32 = new Uint32Array(provingKey); const pkey32 = new Uint32Array(provingKey);
const pPointsA = pkey32[5]; const pPointsA = pkey32[5];
const points = provingKey.slice(pPointsA, pPointsA + nSignals*64); const points = provingKey.slice(pPointsA, pPointsA + nSignals * 64);
const signals = signalsAll.slice(0, nSignals*32); const signals = signalsAll.slice(0, nSignals * 32);
const pr1 = groth16.alloc(96); const pr1 = groth16.alloc(96);
const pPoints = groth16.alloc(points.byteLength); const pPoints = groth16.alloc(points.byteLength);
@ -42,11 +41,10 @@ describe("Basic tests for groth16 proof generator", () => {
const r2 = groth16.bin2g1(groth16.getBin(pr1, 96)); const r2 = groth16.bin2g1(groth16.getBin(pr1, 96));
assert.equal(r1[0],r2[0]); assert.equal(r1[0], r2[0]);
assert.equal(r1[1],r2[1]); assert.equal(r1[1], r2[1]);
groth16.terminate(); groth16.terminate();
}); });
it("It should do a basic point doubling G1", async () => { it("It should do a basic point doubling G1", async () => {
@ -57,12 +55,13 @@ describe("Basic tests for groth16 proof generator", () => {
const proofS = await groth16.proof(signals.buffer, provingKey.buffer); const proofS = await groth16.proof(signals.buffer, provingKey.buffer);
const proof = snarkjs.unstringifyBigInts(proofS); const proof = snarkjs.unstringifyBigInts(proofS);
const verifierKey = snarkjs.unstringifyBigInts(JSON.parse(fs.readFileSync(path.join(__dirname, "data", "verification_key.json"), "utf8"))); const verifierKey = snarkjs.unstringifyBigInts(
JSON.parse(fs.readFileSync(path.join(__dirname, "data", "verification_key.json"), "utf8"))
);
const pub = snarkjs.unstringifyBigInts(JSON.parse(fs.readFileSync(path.join(__dirname, "data", "public.json"), "utf8"))); const pub = snarkjs.unstringifyBigInts(JSON.parse(fs.readFileSync(path.join(__dirname, "data", "public.json"), "utf8")));
assert(snarkjs.groth.isValid(verifierKey, proof, pub)); assert(snarkjs.groth.isValid(verifierKey, proof, pub));
groth16.terminate(); groth16.terminate();
}).timeout(10000000); }).timeout(10000000);
}); });