1
0
Fork 0
mirror of synced 2025-09-23 12:18:44 +00:00
This commit is contained in:
dark64 2022-01-26 14:39:08 +01:00
parent 3046f21e26
commit 7fb5cf01ef
6 changed files with 358 additions and 339 deletions

View file

@ -68,8 +68,8 @@ impl ProgEnum {
pub fn curve(&self) -> &'static str { pub fn curve(&self) -> &'static str {
match self { match self {
ProgEnum::Bls12_381Program(_) => Bls12_377Field::name(),
ProgEnum::Bn128Program(_) => Bn128Field::name(), ProgEnum::Bn128Program(_) => Bn128Field::name(),
ProgEnum::Bls12_381Program(_) => Bls12_381Field::name(),
ProgEnum::Bls12_377Program(_) => Bls12_377Field::name(), ProgEnum::Bls12_377Program(_) => Bls12_377Field::name(),
ProgEnum::Bw6_761Program(_) => Bw6_761Field::name(), ProgEnum::Bw6_761Program(_) => Bw6_761Field::name(),
} }

View file

@ -18,5 +18,5 @@ zokrates_field = { path = "../zokrates_field", default-features = false, feature
zokrates_abi = { path = "../zokrates_abi" } zokrates_abi = { path = "../zokrates_abi" }
console_error_panic_hook = "0.1.6" console_error_panic_hook = "0.1.6"
[package.metadata.wasm-pack.profile.release] # [package.metadata.wasm-pack.profile.release]
wasm-opt = false # wasm-opt = false

131
zokrates_js/index.d.ts vendored
View file

@ -1,5 +1,4 @@
declare module 'zokrates-js' { declare module "zokrates-js" {
export type Curve = "bn128" | "bls12_381" | "bls12_377" | "bw6_761"; export type Curve = "bn128" | "bls12_381" | "bls12_377" | "bw6_761";
export type Backend = "bellman" | "ark"; export type Backend = "bellman" | "ark";
export type Scheme = "g16" | "gm17" | "marlin"; export type Scheme = "g16" | "gm17" | "marlin";
@ -11,79 +10,129 @@ declare module 'zokrates-js' {
export type G2Affine = [Fq2, Fq2]; export type G2Affine = [Fq2, Fq2];
export type ProvingKey = Uint8Array; export type ProvingKey = Uint8Array;
export type ResolveCallback = (location: string, path: string) => ResolverResult; export type ResolveCallback = (
location: string,
path: string
) => ResolverResult;
export interface CompileConfig { export interface CompileConfig {
allow_unconstrained_variables?: boolean, allow_unconstrained_variables?: boolean;
isolate_branches?: boolean isolate_branches?: boolean;
} }
export interface CompileOptions { export interface CompileOptions {
location?: string, location?: string;
resolveCallback?: ResolveCallback, resolveCallback?: ResolveCallback;
config?: CompileConfig config?: CompileConfig;
} }
export interface VerificationKey { export interface VerificationKey {
alpha: G1Affine, alpha: G1Affine;
beta: G2Affine, beta: G2Affine;
gamma: G2Affine, gamma: G2Affine;
delta: G2Affine, delta: G2Affine;
gamma_abc: G1Affine[] gamma_abc: G1Affine[];
} }
export interface ProofPoints { export interface ProofPoints {
a: G1Affine, a: G1Affine;
b: G2Affine, b: G2Affine;
c: G1Affine c: G1Affine;
} }
export interface Proof { export interface Proof {
proof: ProofPoints, proof: ProofPoints;
inputs: string[] inputs: string[];
} }
export interface ResolverResult { export interface ResolverResult {
source: string, source: string;
location: string location: string;
} }
export interface ComputationResult { export interface ComputationResult {
witness: string, witness: string;
output: string output: string;
} }
export interface CompilationArtifacts { export interface CompilationArtifacts {
program: Uint8Array, program: Uint8Array;
abi: string, abi: string;
}
export interface SetupKeypair {
vk: VerificationKey,
pk: ProvingKey,
} }
export type Options = { export interface SetupKeypair {
curve: Scheme, vk: VerificationKey;
backend: Backend, pk: ProvingKey;
scheme: Curve,
} }
export type Options = {
curve: Scheme;
backend: Backend;
scheme: Curve;
};
type AtLeast<T, K extends keyof T> = Partial<T> & Pick<T, K>; type AtLeast<T, K extends keyof T> = Partial<T> & Pick<T, K>;
export type SpecializedZoKratesProvider = {
compile(
source: string,
compileOptions?: CompileOptions
): CompilationArtifacts;
computeWitness(
artifacts: CompilationArtifacts,
args: any[]
): ComputationResult;
setup(program: Uint8Array): SetupKeypair;
universalSetup(size: number): Uint8Array;
setupWithSrs(srs: Uint8Array, program: Uint8Array): SetupKeypair;
generateProof(
program: Uint8Array,
witness: string,
provingKey: Uint8Array
): Proof;
verify(verificationKey: VerificationKey, proof: Proof): boolean;
exportSolidityVerifier(verificationKey: VerificationKey): string;
};
export interface ZoKratesProvider { export interface ZoKratesProvider {
compile(source: string, options?: CompileOptions): CompilationArtifacts; withOptions(options: Options): SpecializedZoKratesProvider;
computeWitness(artifacts: CompilationArtifacts, args: any[]): ComputationResult; compile(
setup(program: Uint8Array, options: AtLeast<Options, "backend" | "scheme">): SetupKeypair; source: string,
setupWithSrs(srs: Uint8Array, program: Uint8Array, options: AtLeast<Options, "backend" | "scheme">): SetupKeypair; compileOptions?: CompileOptions
): CompilationArtifacts;
computeWitness(
artifacts: CompilationArtifacts,
args: any[]
): ComputationResult;
setup(
program: Uint8Array,
options: AtLeast<Options, "backend" | "scheme">
): SetupKeypair;
universalSetup(curve: Curve, size: number): Uint8Array; universalSetup(curve: Curve, size: number): Uint8Array;
exportSolidityVerifier(verificationKey: VerificationKey, options: AtLeast<Options, "curve" | "scheme">): string; setupWithSrs(
generateProof(program: Uint8Array, witness: string, provingKey: Uint8Array, options: AtLeast<Options, "backend" | "scheme">): Proof; srs: Uint8Array,
verify(verificationKey: VerificationKey, proof: Proof, options: Options): boolean; program: Uint8Array,
options: AtLeast<Options, "backend" | "scheme">
): SetupKeypair;
generateProof(
program: Uint8Array,
witness: string,
provingKey: Uint8Array,
options: AtLeast<Options, "backend" | "scheme">
): Proof;
verify(
verificationKey: VerificationKey,
proof: Proof,
options: Options
): boolean;
exportSolidityVerifier(
verificationKey: VerificationKey,
options: AtLeast<Options, "curve" | "scheme">
): string;
} }
export interface Metadata { export interface Metadata {
version: string version: string;
} }
export function initialize(): Promise<ZoKratesProvider>; export function initialize(): Promise<ZoKratesProvider>;

View file

@ -67,14 +67,14 @@ impl<'a> Resolver<Error> for JsResolver<'a> {
) )
.map_err(|_| { .map_err(|_| {
Error::new(format!( Error::new(format!(
"Error thrown in JS callback: could not resolve {}", "Error thrown in JS callback: could not resolve `{}`",
import_location.display() import_location.display()
)) ))
})?; })?;
if value.is_null() || value.is_undefined() { if value.is_null() || value.is_undefined() {
Err(Error::new(format!( Err(Error::new(format!(
"Could not resolve {}", "Could not resolve `{}`",
import_location.display() import_location.display()
))) )))
} else { } else {
@ -210,15 +210,10 @@ pub fn compile(
location: JsValue, location: JsValue,
resolve_callback: &js_sys::Function, resolve_callback: &js_sys::Function,
config: JsValue, config: JsValue,
options: JsValue, curve: JsValue,
) -> Result<JsValue, JsValue> { ) -> Result<JsValue, JsValue> {
let options: serde_json::Value = options.into_serde().unwrap(); let curve = CurveParameter::try_from(curve.as_string().unwrap().as_str())
let curve = CurveParameter::try_from( .map_err(|e| JsValue::from_str(&e))?;
options["curve"]
.as_str()
.ok_or_else(|| JsValue::from_str("missing field `curve` in `options` object"))?,
)
.map_err(|e| JsValue::from_str(&e))?;
match curve { match curve {
CurveParameter::Bn128 => { CurveParameter::Bn128 => {
@ -358,7 +353,7 @@ pub fn universal_setup(curve: JsValue, size: u32) -> Result<Vec<u8>, JsValue> {
Ok(internal::universal_setup_of_size::<Bw6_761Field, Marlin, Ark>(size)) Ok(internal::universal_setup_of_size::<Bw6_761Field, Marlin, Ark>(size))
} }
c => Err(JsValue::from_str(&format!( c => Err(JsValue::from_str(&format!(
"Unsupported curve `{:?}` provided in universal setup", "Unsupported curve `{:?}` provided to universal setup",
c c
))), ))),
} }

View file

@ -1,234 +1,166 @@
const assert = require('assert'); const assert = require("assert");
const { initialize } = require('../node/index.js'); const { initialize } = require("../node/index.js");
describe('tests', function() { describe("tests", function () {
let zokrates; let zokrates;
// initialize once before running tests
before((done) => {
initialize().then((provider) => {
zokrates = provider;
done();
});
});
describe("compilation", () => {
it("should compile", () => {
assert.doesNotThrow(() => {
const artifacts = zokrates.compile("def main() -> field: return 42");
assert.ok(artifacts !== undefined);
});
});
it("should throw on invalid code", () => {
assert.throws(() => zokrates.compile(":-)"));
});
it("should resolve stdlib module", () => {
const stdlib = require("../stdlib.json");
assert.doesNotThrow(() => {
const code = `import "${
Object.keys(stdlib)[0]
}" as func\ndef main(): return`;
zokrates.compile(code);
});
});
it("should resolve user module", () => {
assert.doesNotThrow(() => {
const code =
'import "test" as test\ndef main() -> field: return test()';
const options = {
resolveCallback: (_, path) => {
return {
source: "def main() -> (field): return 1",
location: path,
};
},
};
zokrates.compile(code, options);
});
});
it("should throw on unresolved module", () => {
assert.throws(() => {
const code =
'import "test" as test\ndef main() -> field: return test()';
zokrates.compile(code);
});
});
});
describe("computation", () => {
it("should compute with valid inputs", () => {
assert.doesNotThrow(() => {
const code = "def main(private field a) -> field: return a * a";
const artifacts = zokrates.compile(code);
const result = zokrates.computeWitness(artifacts, ["2"]);
const output = JSON.parse(result.output);
assert.deepEqual(output, ["4"]);
});
});
it("should throw on invalid input count", () => {
assert.throws(() => {
const code = "def main(private field a) -> field: return a * a";
const artifacts = zokrates.compile(code);
zokrates.computeWitness(artifacts, ["1", "2"]);
});
});
it("should throw on invalid input type", () => {
assert.throws(() => {
const code = "def main(private field a) -> field: return a * a";
const artifacts = zokrates.compile(code);
zokrates.computeWitness(artifacts, [true]);
});
});
});
const runWithOptions = (options) => {
let artifacts;
let computationResult;
let keypair;
let proof;
// initialize once before running tests
before((done) => { before((done) => {
initialize().then((provider) => { const code = "def main(private field a) -> field: return a + a";
zokrates = provider; artifacts = zokrates.compile(code, { curve: options.curve });
done(); computationResult = zokrates.computeWitness(artifacts, ["2"]);
}); done();
}); });
describe("compilation", () => { it("setup", () => {
it('should compile', () => { assert.doesNotThrow(() => {
assert.doesNotThrow(() => { if (options.scheme === "marlin") {
const artifacts = zokrates.compile("def main() -> field: return 42"); const srs = zokrates.universalSetup(options.curve, 2);
assert.ok(artifacts !== undefined); keypair = zokrates.setupWithSrs(srs, artifacts.program, options);
}) } else {
}); keypair = zokrates.setup(artifacts.program, options);
}
it('should throw on invalid code', () => { });
assert.throws(() => zokrates.compile(":-)"));
});
it('should resolve stdlib module', () => {
const stdlib = require('../stdlib.json');
assert.doesNotThrow(() => {
const code = `import "${Object.keys(stdlib)[0]}" as func\ndef main(): return`;
zokrates.compile(code);
});
});
it('should resolve user module', () => {
assert.doesNotThrow(() => {
const code = 'import "test" as test\ndef main() -> field: return test()';
const options = {
resolveCallback: (_, path) => {
return {
source: "def main() -> (field): return 1",
location: path
}
}
};
zokrates.compile(code, options);
});
});
it('should throw on unresolved module', () => {
assert.throws(() => {
const code = 'import "test" as test\ndef main() -> field: return test()';
zokrates.compile(code);
});
});
}); });
describe("computation", () => { it("generate proof", () => {
it('should compute with valid inputs', () => { assert.doesNotThrow(() => {
assert.doesNotThrow(() => { proof = zokrates.generateProof(
const code = 'def main(private field a) -> field: return a * a'; artifacts.program,
const artifacts = zokrates.compile(code); computationResult.witness,
keypair.pk,
const result = zokrates.computeWitness(artifacts, ["2"]); options
const output = JSON.parse(result.output); );
assert.deepEqual(output, ["4"]); assert.ok(proof !== undefined);
}); assert.ok(proof.proof.hasOwnProperty("a"));
}); assert.ok(proof.proof.hasOwnProperty("b"));
assert.ok(proof.proof.hasOwnProperty("c"));
it('should throw on invalid input count', () => { assert.equal(proof.inputs.length, 1);
assert.throws(() => { });
const code = 'def main(private field a) -> field: return a * a';
const artifacts = zokrates.compile(code);
zokrates.computeWitness(artifacts, ["1", "2"]);
});
});
it('should throw on invalid input type', () => {
assert.throws(() => {
const code = 'def main(private field a) -> field: return a * a';
const artifacts = zokrates.compile(code);
zokrates.computeWitness(artifacts, [true]);
});
});
}); });
describe("bellman", () => { it("verify with valid proof", () => {
describe("groth16", () => { assert.doesNotThrow(() => {
const options = { assert(zokrates.verify(keypair.vk, proof, options) === true);
backend: "bellman", });
curve: "bn128",
scheme: "g16"
};
let artifacts;
let computationResult;
let keypair;
let proof;
before((done) => {
const code = 'def main(private field a) -> field: return a * a';
artifacts = zokrates.compile(code);
computationResult = zokrates.computeWitness(artifacts, ["2"]);
done();
});
it("setup", () => {
assert.doesNotThrow(() => {
keypair = zokrates.setup(artifacts.program, options);
});
});
it("generate proof", () => {
assert.doesNotThrow(() => {
proof = zokrates.generateProof(artifacts.program, computationResult.witness, keypair.pk, options);
assert.ok(proof !== undefined);
assert.deepEqual(proof.inputs, ["0x0000000000000000000000000000000000000000000000000000000000000004"]);
});
});
it("export solidity verifier", () => {
let verifier = zokrates.exportSolidityVerifier(keypair.vk, options);
assert(verifier.length > 0);
});
it("verify with valid proof", () => {
assert.doesNotThrow(() => {
assert(zokrates.verify(keypair.vk, proof, options) === true);
});
});
it("verify with invalid proof", () => {
// falsify proof
proof["proof"]["a"][0] = "0x0000000000000000000000000000000000000000000000000000000000000000";
assert(zokrates.verify(keypair.vk, proof, options) === false);
});
});
}); });
describe("ark", () => { it("falsify proof", () => {
describe("gm17", () => { let tmp = proof["proof"]["a"][0];
const options = { proof["proof"]["a"][0] = proof["proof"]["a"][1];
backend: "ark", proof["proof"]["a"][1] = tmp;
curve: "bn128", assert(zokrates.verify(keypair.vk, proof, options) === false);
scheme: "gm17"
};
let artifacts;
let computationResult;
let keypair;
let proof;
before((done) => {
const code = 'def main(private field a) -> field: return a * a';
artifacts = zokrates.compile(code);
computationResult = zokrates.computeWitness(artifacts, ["2"]);
done();
});
it("setup", () => {
assert.doesNotThrow(() => {
keypair = zokrates.setup(artifacts.program, options);
});
});
it("generate proof", () => {
assert.doesNotThrow(() => {
proof = zokrates.generateProof(artifacts.program, computationResult.witness, keypair.pk, options);
assert.ok(proof !== undefined);
assert.deepEqual(proof.inputs, ["0x0000000000000000000000000000000000000000000000000000000000000004"]);
});
});
it("verify with valid proof", () => {
assert.doesNotThrow(() => {
assert(zokrates.verify(keypair.vk, proof, options) === true);
});
});
it("verify with invalid proof", () => {
// falsify proof
proof["proof"]["a"][0] = "0x0000000000000000000000000000000000000000000000000000000000000000";
assert(zokrates.verify(keypair.vk, proof, options) === false);
});
});
describe("marlin", () => {
const options = {
backend: "ark",
curve: "bn128",
scheme: "marlin"
};
let artifacts;
let computationResult;
let keypair;
let proof;
before((done) => {
const code = 'def main(private field a, private field b) -> bool: return a * a == b';
artifacts = zokrates.compile(code);
computationResult = zokrates.computeWitness(artifacts, ["2", "4"]);
done();
});
it("setup", () => {
assert.doesNotThrow(() => {
const srs = zokrates.universalSetup("bn128", 4);
keypair = zokrates.setupWithSrs(srs, artifacts.program, options);
});
});
it("generate proof", () => {
assert.doesNotThrow(() => {
proof = zokrates.generateProof(artifacts.program, computationResult.witness, keypair.pk, options);
assert.ok(proof !== undefined);
assert.deepEqual(proof.inputs, ["0x0000000000000000000000000000000000000000000000000000000000000001"]);
});
});
it("verify with valid proof", () => {
assert.doesNotThrow(() => {
assert(zokrates.verify(keypair.vk, proof, options) === true);
});
});
it("verify with invalid proof", () => {
// falsify proof
proof["inputs"][0] = "0x0000000000000000000000000000000000000000000000000000000000000000";
assert(zokrates.verify(keypair.vk, proof, options) === false);
});
});
}); });
}); };
describe("bellman", () => {
describe("groth16", () => {
for (const curve of ["bn128", "bls12_381"]) {
describe(curve, () =>
runWithOptions({ backend: "bellman", scheme: "g16", curve })
);
}
});
});
describe("ark", () => {
for (const scheme of ["gm17", "marlin"]) {
describe(scheme, () => {
for (const curve of ["bn128", "bls12_377", "bw6_761"]) {
describe(curve, () =>
runWithOptions({ backend: "ark", scheme: "gm17", curve })
);
}
});
}
});
});

View file

@ -1,71 +1,114 @@
const getAbsolutePath = (basePath, relativePath) => { const getAbsolutePath = (basePath, relativePath) => {
if (relativePath[0] !== '.') { if (relativePath[0] !== ".") {
return relativePath; return relativePath;
} }
var stack = basePath.split('/'); var stack = basePath.split("/");
var chunks = relativePath.split('/'); var chunks = relativePath.split("/");
stack.pop(); stack.pop();
for (var i = 0; i < chunks.length; i++) { for (var i = 0; i < chunks.length; i++) {
if (chunks[i] == '.') { if (chunks[i] == ".") {
continue; continue;
} else if (chunks[i] == '..') { } else if (chunks[i] == "..") {
stack.pop(); stack.pop();
} else { } else {
stack.push(chunks[i]); stack.push(chunks[i]);
}
} }
return stack.join('/'); }
} return stack.join("/");
};
const getImportPath = (currentLocation, importLocation) => { const getImportPath = (currentLocation, importLocation) => {
let path = getAbsolutePath(currentLocation, importLocation); let path = getAbsolutePath(currentLocation, importLocation);
const extension = path.slice((path.lastIndexOf(".") - 1 >>> 0) + 2); const extension = path.slice(((path.lastIndexOf(".") - 1) >>> 0) + 2);
return extension ? path : path.concat('.zok'); return extension ? path : path.concat(".zok");
} };
module.exports = (dep) => { module.exports = (dep) => {
const { zokrates, stdlib } = dep; const { zokrates, stdlib } = dep;
const resolveFromStdlib = (currentLocation, importLocation) => { const resolveFromStdlib = (currentLocation, importLocation) => {
let key = getImportPath(currentLocation, importLocation); let key = getImportPath(currentLocation, importLocation);
let source = stdlib[key]; let source = stdlib[key];
return source ? { source, location: key } : null; return source ? { source, location: key } : null;
} };
return { const defaultProvider = {
compile: (source, options = {}) => { compile: (source, compileOptions = {}) => {
const { curve = "bn128", location = "main.zok", resolveCallback = () => null, config = {} } = options; const {
const callback = (currentLocation, importLocation) => { curve = "bn128",
return resolveFromStdlib(currentLocation, importLocation) || resolveCallback(currentLocation, importLocation); location = "main.zok",
}; resolveCallback = () => null,
const { program, abi } = zokrates.compile(source, location, callback, config, { curve }); config = {},
return { } = compileOptions;
program: new Uint8Array(program), const callback = (currentLocation, importLocation) => {
abi return (
} resolveFromStdlib(currentLocation, importLocation) ||
}, resolveCallback(currentLocation, importLocation)
computeWitness: (artifacts, args) => { );
const { program, abi } = artifacts; };
return zokrates.compute_witness(program, abi, JSON.stringify(Array.from(args))); const { program, abi } = zokrates.compile(
}, source,
setup: (program, options) => { location,
return zokrates.setup(program, options); callback,
}, config,
universalSetup: (curve, size) => { curve
return zokrates.universal_setup(curve, size); );
}, return {
setupWithSrs: (srs, program, options) => { program: new Uint8Array(program),
return zokrates.setup_with_srs(srs, program, options); abi,
}, };
generateProof: (program, witness, provingKey, options) => { },
return zokrates.generate_proof(program, witness, provingKey, options); computeWitness: (artifacts, args) => {
}, const { program, abi } = artifacts;
verify: (vk, proof, options) => { return zokrates.compute_witness(
return zokrates.verify(vk, proof, options); program,
}, abi,
exportSolidityVerifier: (vk, options) => { JSON.stringify(Array.from(args))
return zokrates.export_solidity_verifier(vk, options); );
} },
} setup: (program, options) => {
}; return zokrates.setup(program, options);
},
universalSetup: (curve, size) => {
return zokrates.universal_setup(curve, size);
},
setupWithSrs: (srs, program, options) => {
return zokrates.setup_with_srs(srs, program, options);
},
generateProof: (program, witness, provingKey, options) => {
return zokrates.generate_proof(program, witness, provingKey, options);
},
verify: (vk, proof, options) => {
return zokrates.verify(vk, proof, options);
},
exportSolidityVerifier: (vk, options) => {
return zokrates.export_solidity_verifier(vk, options);
},
};
const withOptions = (options) => ({
compile: (source, compileOptions = {}) =>
defaultProvider.compile(source, {
...compileOptions,
curve: options.curve,
}),
computeWitness: (artifacts, args) =>
defaultProvider.computeWitness(artifacts, args),
setup: (program) => defaultProvider.setup(program, options),
universalSetup: (size) =>
defaultProvider.universalSetup(options.curve, size),
setupWithSrs: (srs, program) =>
defaultProvider.setupWithSrs(srs, program, options),
generateProof: (program, witness, provingKey) =>
defaultProvider.generateProof(program, witness, provingKey, options),
verify: (vk, proof) => defaultProvider.verify(vk, proof, options),
exportSolidityVerifier: (vk) =>
defaultProvider.exportSolidityVerifier(vk, options),
});
return {
withOptions,
...defaultProvider,
};
};