@ -0,0 +1,33 @@ |
|||||
|
module.exports = { |
||||
|
"plugins": [ |
||||
|
"mocha" |
||||
|
], |
||||
|
"env": { |
||||
|
"es6": true, |
||||
|
"node": true, |
||||
|
"mocha": true |
||||
|
}, |
||||
|
"parserOptions": { |
||||
|
"ecmaVersion": 2017 |
||||
|
}, |
||||
|
"extends": "eslint:recommended", |
||||
|
"rules": { |
||||
|
"indent": [ |
||||
|
"error", |
||||
|
4 |
||||
|
], |
||||
|
"linebreak-style": [ |
||||
|
"error", |
||||
|
"unix" |
||||
|
], |
||||
|
"quotes": [ |
||||
|
"error", |
||||
|
"double" |
||||
|
], |
||||
|
"semi": [ |
||||
|
"error", |
||||
|
"always" |
||||
|
], |
||||
|
"mocha/no-exclusive-tests": "error" |
||||
|
} |
||||
|
}; |
@ -0,0 +1,63 @@ |
|||||
|
# Logs |
||||
|
logs |
||||
|
*.log |
||||
|
npm-debug.log* |
||||
|
yarn-debug.log* |
||||
|
yarn-error.log* |
||||
|
|
||||
|
# Runtime data |
||||
|
pids |
||||
|
*.pid |
||||
|
*.seed |
||||
|
*.pid.lock |
||||
|
|
||||
|
# Directory for instrumented libs generated by jscoverage/JSCover |
||||
|
lib-cov |
||||
|
|
||||
|
# Coverage directory used by tools like istanbul |
||||
|
coverage |
||||
|
|
||||
|
# nyc test coverage |
||||
|
.nyc_output |
||||
|
|
||||
|
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) |
||||
|
.grunt |
||||
|
|
||||
|
# Bower dependency directory (https://bower.io/) |
||||
|
bower_components |
||||
|
|
||||
|
# node-waf configuration |
||||
|
.lock-wscript |
||||
|
|
||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html) |
||||
|
build/Release |
||||
|
|
||||
|
# Dependency directories |
||||
|
node_modules/ |
||||
|
jspm_packages/ |
||||
|
|
||||
|
# Typescript v1 declaration files |
||||
|
typings/ |
||||
|
|
||||
|
# Optional npm cache directory |
||||
|
.npm |
||||
|
|
||||
|
# Optional eslint cache |
||||
|
.eslintcache |
||||
|
|
||||
|
# Optional REPL history |
||||
|
.node_repl_history |
||||
|
|
||||
|
# Output of 'npm pack' |
||||
|
*.tgz |
||||
|
|
||||
|
# Yarn Integrity file |
||||
|
.yarn-integrity |
||||
|
|
||||
|
# dotenv environment variables file |
||||
|
.env |
||||
|
|
||||
|
# next.js build output |
||||
|
.next |
||||
|
|
||||
|
tmp |
@ -0,0 +1,107 @@ |
|||||
|
# javascript implementation of zkSnark |
||||
|
|
||||
|
This is a javascript implementation of zkSnarks. |
||||
|
|
||||
|
This library allows to do the trusted setup, generate proofs and verify the proofs. |
||||
|
|
||||
|
This library uses the compiled circuits generated by the jaz compiler. |
||||
|
|
||||
|
## Install |
||||
|
|
||||
|
``` |
||||
|
npm install zkSnark |
||||
|
``` |
||||
|
|
||||
|
## Usage |
||||
|
|
||||
|
### import |
||||
|
|
||||
|
``` |
||||
|
const zkSnark = require("zksnark"); |
||||
|
``` |
||||
|
|
||||
|
### Load a circuit. |
||||
|
|
||||
|
``` |
||||
|
// "myCircuit.cir" is the output of the jaz compiler |
||||
|
|
||||
|
const circuitDef = JSON.parse(fs.readFileSync("myCircuit.cir", "utf8")); |
||||
|
const circuit = new zkSnark.Circuit(circuitDef); |
||||
|
``` |
||||
|
|
||||
|
### Inspect the circuit. |
||||
|
|
||||
|
``` |
||||
|
// `signalId` can always be a number or an alias string |
||||
|
|
||||
|
circuit.m; // number of constrains |
||||
|
circuit.n; // number of signals |
||||
|
circuit.p; // number of public signals (nPublicInputs + nOutputs) |
||||
|
|
||||
|
// The array of signals is always sorted in this order: |
||||
|
// [ outputs, publicInputs, privedInputs, internalSignals, constants] |
||||
|
|
||||
|
// returns a,b and c coeficients of the `signalId` on a given `constrain` |
||||
|
circuit.a(constrain, signalId) |
||||
|
circuit.b(constrain, signalId) |
||||
|
circuit.c(constrain, signalId) |
||||
|
|
||||
|
circuit.nOutputs // number of public outputs |
||||
|
circuit.nPublicInputs // number of public inputs |
||||
|
circuit.nPrivateInputs // number of private inputs |
||||
|
circuit.nInputs // number of inputs ( nPublicInputs + nPrivateInputs) |
||||
|
|
||||
|
circuit.outputIdx(i) // returns the index of the i'th output |
||||
|
circuit.inputIdx(i) // returns the index of the i'th input |
||||
|
circuit.inputPublicIdx(i) // returns the index of the i'th public input |
||||
|
circuit.inputPrivateIdx(i) // returns the index of the i'th private input |
||||
|
|
||||
|
// returns signal Idx given a signalId |
||||
|
// if the idx >= n , it is a constant |
||||
|
// if the idx == -1, the signal does not exist |
||||
|
circuit.signalId2idx(signalId); |
||||
|
|
||||
|
// returns an array aliases names for a given signalId |
||||
|
circuit.signalNames(signalId) |
||||
|
|
||||
|
// input is a key value object where keys are the signal names |
||||
|
// of all the inputs (public and private) |
||||
|
// returns an array of values that represent the witness |
||||
|
circuit.generateWitness(input) |
||||
|
``` |
||||
|
|
||||
|
### Trusted setup |
||||
|
|
||||
|
``` |
||||
|
const setup = zkSnark.setup(circuit); |
||||
|
fs.writeFileSink("myCircuit.vk_proof", JSON.stringify(setup.vk_proof), "utf8"); |
||||
|
fs.writeFileSink("myCircuit.vk_verifier", JSON.stringify(setup.vk_verifier), "utf8"); |
||||
|
setup.toxic // Must be discarded. |
||||
|
``` |
||||
|
|
||||
|
### Generate proof |
||||
|
|
||||
|
``` |
||||
|
const circuitDef = JSON.parse(fs.readFileSync("myCircuit.cir", "utf8")); |
||||
|
const circuit = new zkSnark.Circuit(circuitDef); |
||||
|
const input = { |
||||
|
"main.pubIn1": "123", |
||||
|
"main.out1": "456" |
||||
|
} |
||||
|
const witness = circuit.generateWitness(input); |
||||
|
const vk_proof = JSON.parse(fs.readFileSync("myCircuit.vk_proof", "utf8")); |
||||
|
|
||||
|
const {proof, publicSignals} = zkSnark.genProof(vk_proof, witness); |
||||
|
``` |
||||
|
|
||||
|
### Verifier |
||||
|
|
||||
|
``` |
||||
|
const vk_verifier = JSON.parse(fs.readFileSync("myCircuit.vk_verifier", "utf8")); |
||||
|
|
||||
|
if (zkSnark.isValid(vk_verifier, proof, publicSignals)) { |
||||
|
console.log("The proof is valid"); |
||||
|
} else { |
||||
|
console.log("The proof is not valid"); |
||||
|
} |
||||
|
``` |
@ -0,0 +1,4 @@ |
|||||
|
exports.Circuit = require "./src/circuit.js"; |
||||
|
exports.setup = require "./src/setup.js"; |
||||
|
exports.genProof = require "./src/prover.js"; |
||||
|
exports.isValid = require "./src/verifier.js"; |
@ -0,0 +1,26 @@ |
|||||
|
{ |
||||
|
"name": "zksnark", |
||||
|
"version": "0.0.1", |
||||
|
"description": "zkSnark implementation in javascript", |
||||
|
"main": "index.js", |
||||
|
"scripts": { |
||||
|
"test": "echo \"Error: no test specified\" && exit 1" |
||||
|
}, |
||||
|
"keywords": [ |
||||
|
"zksnark", |
||||
|
"zcash", |
||||
|
"ethereum", |
||||
|
"zero", |
||||
|
"knowlage", |
||||
|
"cryptography", |
||||
|
"circuit" |
||||
|
], |
||||
|
"author": "Jordi Baylina", |
||||
|
"license": "GPL-3.0", |
||||
|
"dependencies": { |
||||
|
"eslint": "^5.3.0" |
||||
|
}, |
||||
|
"devDependencies": { |
||||
|
"eslint-plugin-mocha": "^5.1.0" |
||||
|
} |
||||
|
} |
@ -0,0 +1,6 @@ |
|||||
|
|
||||
|
module.exports = class Circuit { |
||||
|
constructor(circuitDef) { |
||||
|
|
||||
|
} |
||||
|
}; |
@ -0,0 +1,29 @@ |
|||||
|
const bigInt = require("big-integer"); |
||||
|
const ZnField = require("./znfield.js"); |
||||
|
|
||||
|
module.eports = class G1Curve { |
||||
|
|
||||
|
constructor() { |
||||
|
this.F = new ZnField(bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208583")); |
||||
|
this.g = [ |
||||
|
|
||||
|
]; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
add(p1, p2) { |
||||
|
// TODO
|
||||
|
throw new Error("Not Implementted"); |
||||
|
} |
||||
|
|
||||
|
double(p1) { |
||||
|
// TODO
|
||||
|
throw new Error("Not Implementted"); |
||||
|
} |
||||
|
|
||||
|
mulEscalar(p1, e) { |
||||
|
// TODO
|
||||
|
throw new Error("Not Implementted"); |
||||
|
} |
||||
|
|
||||
|
}; |
@ -0,0 +1,28 @@ |
|||||
|
const bigInt = require("big-integer"); |
||||
|
const ZnField = require("./znfield.js"); |
||||
|
|
||||
|
module.eports = class G2Curve { |
||||
|
|
||||
|
constructor() { |
||||
|
this.F = new ZnField(bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208583")); |
||||
|
this.g = [ |
||||
|
|
||||
|
]; |
||||
|
} |
||||
|
|
||||
|
add(p1, p2) { |
||||
|
// TODO
|
||||
|
throw new Error("Not Implementted"); |
||||
|
} |
||||
|
|
||||
|
double(p1) { |
||||
|
// TODO
|
||||
|
throw new Error("Not Implementted"); |
||||
|
} |
||||
|
|
||||
|
mulEscalar(p1, e) { |
||||
|
// TODO
|
||||
|
throw new Error("Not Implementted"); |
||||
|
} |
||||
|
|
||||
|
}; |
@ -0,0 +1,10 @@ |
|||||
|
/* |
||||
|
This module calculate the pairing of p1 and p2 where p1 in G1 and p2 in G2 |
||||
|
*/ |
||||
|
|
||||
|
const bigInt = require("big-integer"); |
||||
|
|
||||
|
module.exports = function pairing(p1, p2) { |
||||
|
// TODO
|
||||
|
throw new Error("Not Implementted"); |
||||
|
}; |
@ -0,0 +1,46 @@ |
|||||
|
/* |
||||
|
This library do operations on polinomials where their coefficients are in field F |
||||
|
|
||||
|
The polynomial P(x) = p0 + p1 * x + p2 * x^2 + p3 * x^3, ... |
||||
|
is represented by the array [ p0, p1, p2, p3, ... ] |
||||
|
*/ |
||||
|
|
||||
|
class PolField { |
||||
|
constructor (F) { |
||||
|
this.F = F; |
||||
|
} |
||||
|
|
||||
|
_reduce(a) { |
||||
|
let i = a.length-1; |
||||
|
while ((i>=0) && (this.F.isZero(a[i])) ) i--; |
||||
|
return (i < a.length-1) ? a.slice(0, i+1) : a; |
||||
|
} |
||||
|
|
||||
|
add(a, b) { |
||||
|
const maxGrade = Math.max(a.length, b.length); |
||||
|
const res = new Array(maxGrade); |
||||
|
for (let i=0; i<maxGrade; i++) { |
||||
|
res[i] = this.F.add(a[i], b[i]); |
||||
|
} |
||||
|
return this._reduce(res); |
||||
|
} |
||||
|
|
||||
|
sub(a, b) { |
||||
|
throw new Error("Not Implementted"); |
||||
|
} |
||||
|
|
||||
|
mul(a, b) { |
||||
|
throw new Error("Not Implementted"); |
||||
|
} |
||||
|
|
||||
|
div(a, b) { |
||||
|
throw new Error("Not Implementted"); |
||||
|
} |
||||
|
|
||||
|
lagrange(points) { |
||||
|
throw new Error("Not Implementted"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
module.exports = PolField; |
@ -0,0 +1,5 @@ |
|||||
|
|
||||
|
|
||||
|
module.exports = function genProof(vk_proof, witness) { |
||||
|
|
||||
|
} |
@ -0,0 +1,5 @@ |
|||||
|
|
||||
|
|
||||
|
module.exports = function setup(circuit) { |
||||
|
|
||||
|
} |
@ -0,0 +1,4 @@ |
|||||
|
|
||||
|
module.exports = function isValid(vk_verifier, proof, publicSignals) { |
||||
|
|
||||
|
} |
@ -0,0 +1,39 @@ |
|||||
|
|
||||
|
|
||||
|
class ZnField { |
||||
|
constructor(n) { |
||||
|
this.n = n; |
||||
|
} |
||||
|
|
||||
|
add(a, b) { |
||||
|
const maxGrade = Math.max(a.length, b.length); |
||||
|
const res = new Array(maxGrade); |
||||
|
for (let i=0; i<maxGrade; i++) { |
||||
|
res[i] = this.F.add(a[i], b[i]); |
||||
|
} |
||||
|
return this._reduce(res); |
||||
|
} |
||||
|
|
||||
|
sub(a, b) { |
||||
|
// TODO
|
||||
|
throw new Error("Not Implementted"); |
||||
|
} |
||||
|
|
||||
|
mul(a, b) { |
||||
|
// TODO
|
||||
|
throw new Error("Not Implementted"); |
||||
|
} |
||||
|
|
||||
|
inverse(a, b) { |
||||
|
// TODO
|
||||
|
throw new Error("Not Implementted"); |
||||
|
} |
||||
|
|
||||
|
div(a, b) { |
||||
|
// TODO
|
||||
|
throw new Error("Not Implementted"); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
module.exports = ZnField; |