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 {
match self {
ProgEnum::Bls12_381Program(_) => Bls12_377Field::name(),
ProgEnum::Bn128Program(_) => Bn128Field::name(),
ProgEnum::Bls12_381Program(_) => Bls12_381Field::name(),
ProgEnum::Bls12_377Program(_) => Bls12_377Field::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" }
console_error_panic_hook = "0.1.6"
[package.metadata.wasm-pack.profile.release]
wasm-opt = false
# [package.metadata.wasm-pack.profile.release]
# 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 Backend = "bellman" | "ark";
export type Scheme = "g16" | "gm17" | "marlin";
@ -11,79 +10,129 @@ declare module 'zokrates-js' {
export type G2Affine = [Fq2, Fq2];
export type ProvingKey = Uint8Array;
export type ResolveCallback = (location: string, path: string) => ResolverResult;
export type ResolveCallback = (
location: string,
path: string
) => ResolverResult;
export interface CompileConfig {
allow_unconstrained_variables?: boolean,
isolate_branches?: boolean
allow_unconstrained_variables?: boolean;
isolate_branches?: boolean;
}
export interface CompileOptions {
location?: string,
resolveCallback?: ResolveCallback,
config?: CompileConfig
location?: string;
resolveCallback?: ResolveCallback;
config?: CompileConfig;
}
export interface VerificationKey {
alpha: G1Affine,
beta: G2Affine,
gamma: G2Affine,
delta: G2Affine,
gamma_abc: G1Affine[]
alpha: G1Affine;
beta: G2Affine;
gamma: G2Affine;
delta: G2Affine;
gamma_abc: G1Affine[];
}
export interface ProofPoints {
a: G1Affine,
b: G2Affine,
c: G1Affine
a: G1Affine;
b: G2Affine;
c: G1Affine;
}
export interface Proof {
proof: ProofPoints,
inputs: string[]
proof: ProofPoints;
inputs: string[];
}
export interface ResolverResult {
source: string,
location: string
source: string;
location: string;
}
export interface ComputationResult {
witness: string,
output: string
witness: string;
output: string;
}
export interface CompilationArtifacts {
program: Uint8Array,
abi: string,
}
export interface SetupKeypair {
vk: VerificationKey,
pk: ProvingKey,
program: Uint8Array;
abi: string;
}
export type Options = {
curve: Scheme,
backend: Backend,
scheme: Curve,
export interface SetupKeypair {
vk: VerificationKey;
pk: ProvingKey;
}
export type Options = {
curve: Scheme;
backend: Backend;
scheme: Curve;
};
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 {
compile(source: string, options?: CompileOptions): CompilationArtifacts;
computeWitness(artifacts: CompilationArtifacts, args: any[]): ComputationResult;
setup(program: Uint8Array, options: AtLeast<Options, "backend" | "scheme">): SetupKeypair;
setupWithSrs(srs: Uint8Array, program: Uint8Array, options: AtLeast<Options, "backend" | "scheme">): SetupKeypair;
withOptions(options: Options): SpecializedZoKratesProvider;
compile(
source: string,
compileOptions?: CompileOptions
): CompilationArtifacts;
computeWitness(
artifacts: CompilationArtifacts,
args: any[]
): ComputationResult;
setup(
program: Uint8Array,
options: AtLeast<Options, "backend" | "scheme">
): SetupKeypair;
universalSetup(curve: Curve, size: number): Uint8Array;
exportSolidityVerifier(verificationKey: VerificationKey, options: AtLeast<Options, "curve" | "scheme">): string;
generateProof(program: Uint8Array, witness: string, provingKey: Uint8Array, options: AtLeast<Options, "backend" | "scheme">): Proof;
verify(verificationKey: VerificationKey, proof: Proof, options: Options): boolean;
setupWithSrs(
srs: Uint8Array,
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 {
version: string
version: string;
}
export function initialize(): Promise<ZoKratesProvider>;

View file

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

View file

@ -1,234 +1,166 @@
const assert = require('assert');
const { initialize } = require('../node/index.js');
const assert = require("assert");
const { initialize } = require("../node/index.js");
describe('tests', function() {
let zokrates;
describe("tests", function () {
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) => {
initialize().then((provider) => {
zokrates = provider;
done();
});
const code = "def main(private field a) -> field: return a + a";
artifacts = zokrates.compile(code, { curve: options.curve });
computationResult = zokrates.computeWitness(artifacts, ["2"]);
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);
});
});
it("setup", () => {
assert.doesNotThrow(() => {
if (options.scheme === "marlin") {
const srs = zokrates.universalSetup(options.curve, 2);
keypair = zokrates.setupWithSrs(srs, artifacts.program, options);
} else {
keypair = zokrates.setup(artifacts.program, options);
}
});
});
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]);
});
});
it("generate proof", () => {
assert.doesNotThrow(() => {
proof = zokrates.generateProof(
artifacts.program,
computationResult.witness,
keypair.pk,
options
);
assert.ok(proof !== undefined);
assert.ok(proof.proof.hasOwnProperty("a"));
assert.ok(proof.proof.hasOwnProperty("b"));
assert.ok(proof.proof.hasOwnProperty("c"));
assert.equal(proof.inputs.length, 1);
});
});
describe("bellman", () => {
describe("groth16", () => {
const options = {
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);
});
});
it("verify with valid proof", () => {
assert.doesNotThrow(() => {
assert(zokrates.verify(keypair.vk, proof, options) === true);
});
});
describe("ark", () => {
describe("gm17", () => {
const options = {
backend: "ark",
curve: "bn128",
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);
});
});
it("falsify proof", () => {
let tmp = proof["proof"]["a"][0];
proof["proof"]["a"][0] = proof["proof"]["a"][1];
proof["proof"]["a"][1] = tmp;
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) => {
if (relativePath[0] !== '.') {
return relativePath;
}
var stack = basePath.split('/');
var chunks = relativePath.split('/');
stack.pop();
if (relativePath[0] !== ".") {
return relativePath;
}
var stack = basePath.split("/");
var chunks = relativePath.split("/");
stack.pop();
for (var i = 0; i < chunks.length; i++) {
if (chunks[i] == '.') {
continue;
} else if (chunks[i] == '..') {
stack.pop();
} else {
stack.push(chunks[i]);
}
for (var i = 0; i < chunks.length; i++) {
if (chunks[i] == ".") {
continue;
} else if (chunks[i] == "..") {
stack.pop();
} else {
stack.push(chunks[i]);
}
return stack.join('/');
}
}
return stack.join("/");
};
const getImportPath = (currentLocation, importLocation) => {
let path = getAbsolutePath(currentLocation, importLocation);
const extension = path.slice((path.lastIndexOf(".") - 1 >>> 0) + 2);
return extension ? path : path.concat('.zok');
}
let path = getAbsolutePath(currentLocation, importLocation);
const extension = path.slice(((path.lastIndexOf(".") - 1) >>> 0) + 2);
return extension ? path : path.concat(".zok");
};
module.exports = (dep) => {
const { zokrates, stdlib } = dep;
const { zokrates, stdlib } = dep;
const resolveFromStdlib = (currentLocation, importLocation) => {
let key = getImportPath(currentLocation, importLocation);
let source = stdlib[key];
return source ? { source, location: key } : null;
}
const resolveFromStdlib = (currentLocation, importLocation) => {
let key = getImportPath(currentLocation, importLocation);
let source = stdlib[key];
return source ? { source, location: key } : null;
};
return {
compile: (source, options = {}) => {
const { curve = "bn128", location = "main.zok", resolveCallback = () => null, config = {} } = options;
const callback = (currentLocation, importLocation) => {
return resolveFromStdlib(currentLocation, importLocation) || resolveCallback(currentLocation, importLocation);
};
const { program, abi } = zokrates.compile(source, location, callback, config, { curve });
return {
program: new Uint8Array(program),
abi
}
},
computeWitness: (artifacts, args) => {
const { program, abi } = artifacts;
return zokrates.compute_witness(program, abi, JSON.stringify(Array.from(args)));
},
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 defaultProvider = {
compile: (source, compileOptions = {}) => {
const {
curve = "bn128",
location = "main.zok",
resolveCallback = () => null,
config = {},
} = compileOptions;
const callback = (currentLocation, importLocation) => {
return (
resolveFromStdlib(currentLocation, importLocation) ||
resolveCallback(currentLocation, importLocation)
);
};
const { program, abi } = zokrates.compile(
source,
location,
callback,
config,
curve
);
return {
program: new Uint8Array(program),
abi,
};
},
computeWitness: (artifacts, args) => {
const { program, abi } = artifacts;
return zokrates.compute_witness(
program,
abi,
JSON.stringify(Array.from(args))
);
},
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,
};
};