1
0
Fork 0
mirror of synced 2025-09-23 04:08:33 +00:00

refactor zokrates-js, add backend option

This commit is contained in:
dark64 2022-08-09 15:15:04 +02:00
parent 2a9e619250
commit 4b83ebc79f
15 changed files with 424 additions and 8118 deletions

11
Cargo.lock generated
View file

@ -1480,6 +1480,12 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "json"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd"
[[package]]
name = "keccak"
version = "0.1.2"
@ -3213,13 +3219,18 @@ dependencies = [
"console_error_panic_hook",
"indexmap",
"js-sys",
"json",
"lazy_static",
"serde",
"serde_json",
"toml",
"typed-arena",
"walkdir",
"wasm-bindgen",
"zokrates_abi",
"zokrates_ark",
"zokrates_ast",
"zokrates_bellman",
"zokrates_circom",
"zokrates_common",
"zokrates_core",

View file

@ -64,14 +64,19 @@ Returns a `ZoKratesProvider` configured with given options.
```js
initialize().then((defaultProvider) => {
let zokratesProvider = defaultProvider.withOptions({ curve: "bls12_381", scheme: "g16" });
let zokratesProvider = defaultProvider.withOptions({
backend: "ark",
curve: "bls12_381",
scheme: "g16"
});
// ...
});
```
Options:
* `curve` - Elliptic curve (`bn128` | `bls12_381` | `bls12_377` | `bw6_761`)
* `scheme` - Proving scheme (`g16` | `gm17` | `marlin`)
* `backend` - Backend (options: `ark` | `bellman`, default: `ark`)
* `curve` - Elliptic curve (options: `bn128` | `bls12_381` | `bls12_377` | `bw6_761`, default: `bn128`)
* `scheme` - Proving scheme (options: `g16` | `gm17` | `marlin`, default: `g16`)
Returns: `ZoKratesProvider`

View file

@ -106,6 +106,8 @@ impl Interpreter {
}
writeln!(log_stream).map_err(|_| Error::LogStream)?;
log_stream.flush().map_err(|_| Error::LogStream)?;
}
}
}

View file

@ -13,14 +13,21 @@ serde = { version = "^1.0.59", features = ["derive"] }
serde_json = { version = "1.0", features = ["preserve_order"] }
wasm-bindgen = { version = "0.2.46", features = ["serde-serialize"] }
typed-arena = "1.4.1"
zokrates_core = { path = "../zokrates_core", default-features = false, features = ["ark"] }
lazy_static = "1.4.0"
zokrates_core = { path = "../zokrates_core", default-features = false, features = ["ark", "bellman"] }
zokrates_ark = { path = "../zokrates_ark", default-features = false}
zokrates_common = { path = "../zokrates_common", default-features = false, features = ["ark"] }
zokrates_bellman = { path = "../zokrates_bellman", default-features = false}
zokrates_common = { path = "../zokrates_common", default-features = false, features = ["ark", "bellman"] }
zokrates_proof_systems = { path = "../zokrates_proof_systems", default-features = false }
zokrates_ast = { path = "../zokrates_ast", default-features = false, features = ["ark"] }
zokrates_interpreter = { path = "../zokrates_interpreter", default-features = false, features = ["ark"] }
zokrates_ast = { path = "../zokrates_ast", default-features = false, features = ["ark", "bellman"] }
zokrates_interpreter = { path = "../zokrates_interpreter", default-features = false, features = ["ark", "bellman"] }
zokrates_field = { path = "../zokrates_field", default-features = false }
zokrates_abi = { path = "../zokrates_abi", default-features = false, features = ["ark"] }
zokrates_abi = { path = "../zokrates_abi", default-features = false, features = ["ark", "bellman"] }
zokrates_circom = { path = "../zokrates_circom" }
console_error_panic_hook = "0.1.6"
indexmap = "~1.6.2" # see https://github.com/rustwasm/wasm-bindgen/issues/2770#issuecomment-1041102532
indexmap = "~1.6.2" # see https://github.com/rustwasm/wasm-bindgen/issues/2770#issuecomment-1041102532
[build-dependencies]
json = "0.12.4"
walkdir = "2.3.2"
toml = "0.5.9"

45
zokrates_js/build.rs Normal file
View file

@ -0,0 +1,45 @@
use std::path::Path;
use std::{env, fs};
use walkdir::WalkDir;
fn main() {
export_stdlib_js();
export_metadata();
}
fn export_stdlib_js() {
let root = "../zokrates_stdlib/stdlib";
let mut stdlib = json::JsonValue::new_object();
for entry in WalkDir::new(root)
.into_iter()
.filter_map(Result::ok)
.filter(|e| !e.file_type().is_dir())
{
let path: &Path = entry.path();
let source = fs::read_to_string(path).unwrap();
stdlib
.insert(path.strip_prefix(root).unwrap().to_str().unwrap(), source)
.unwrap();
}
let out_dir = env::var_os("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("stdlib.json");
fs::write(dest_path, stdlib.dump()).unwrap();
}
fn export_metadata() {
let path = "../zokrates_cli/Cargo.toml";
let config: toml::Value = dbg!(toml::from_str(&fs::read_to_string(path).unwrap()).unwrap());
let mut metadata = json::JsonValue::new_object();
metadata
.insert("version", config["package"]["version"].as_str().unwrap())
.unwrap();
let out_dir = env::var_os("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("metadata.json");
fs::write(dest_path, metadata.dump()).unwrap();
}

View file

@ -1,41 +0,0 @@
const gulp = require("gulp");
const dree = require("dree");
const fs = require("fs");
const path = require("path");
const toml = require("toml");
const stdlibRoot = "../zokrates_stdlib/stdlib";
const options = {
extensions: ["zok"],
};
// Serializes the standard library directory tree to a js file.
gulp.task("stdlib", (done) => {
var stdlib = {};
dree.scan(stdlibRoot, options, function (file) {
const content = fs.readFileSync(file.path).toString();
stdlib[file.relativePath] = content;
});
fs.writeFileSync(
path.resolve(__dirname, "stdlib.js"),
`module.exports = ${JSON.stringify(stdlib)}`
);
done();
});
gulp.task("metadata", (done) => {
const config = toml.parse(
fs.readFileSync("../zokrates_cli/Cargo.toml").toString()
);
const metadata = JSON.stringify({
version: config.package.version,
});
fs.writeFileSync(
path.resolve(__dirname, "metadata.js"),
`module.exports = ${metadata}`
);
done();
});
gulp.task("setup", gulp.parallel("stdlib", "metadata"));

View file

@ -1,4 +1,5 @@
declare module "zokrates-js" {
export type Backend = "ark" | "bellman";
export type Curve = "bn128" | "bls12_381" | "bls12_377" | "bw6_761";
export type Scheme = "g16" | "gm17" | "marlin";
@ -12,6 +13,7 @@ declare module "zokrates-js" {
export interface CompileConfig {
isolate_branches?: boolean;
debug?: boolean;
}
export interface CompileOptions {
@ -63,6 +65,7 @@ declare module "zokrates-js" {
}
export type Options = {
backend: Backend;
scheme: Scheme;
curve: Curve;
};
@ -91,6 +94,7 @@ declare module "zokrates-js" {
utils: {
formatProof(proof: Proof): any[];
};
metadata(): Metadata;
}
export interface Metadata {
@ -98,5 +102,4 @@ declare module "zokrates-js" {
}
export function initialize(): Promise<ZoKratesProvider>;
export var metadata: Metadata;
}

View file

@ -1,10 +1,8 @@
import wrapper from "./wrapper.js";
import stdlib from "./stdlib.js";
import metadata from "./metadata.js";
import lib from "./lib.js";
const initialize = async () => {
const zokrates = await import("./pkg/index.js");
return wrapper({ zokrates, stdlib });
const pkg = await import("./pkg/index.js");
return lib(pkg);
};
export { initialize, metadata };
export { initialize };

View file

@ -1,38 +1,4 @@
const getAbsolutePath = (basePath, relativePath) => {
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]);
}
}
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");
};
module.exports = (dep) => {
const { zokrates, stdlib } = dep;
const resolveFromStdlib = (currentLocation, importLocation) => {
let key = getImportPath(currentLocation, importLocation);
let source = stdlib[key];
return source ? { source, location: key } : null;
};
module.exports = (pkg) => {
const defaultProvider = {
compile: (source, compileOptions = {}) => {
var {
@ -45,31 +11,27 @@ module.exports = (dep) => {
config = { snarkjs, ...config };
const callback = (currentLocation, importLocation) => {
return (
resolveFromStdlib(currentLocation, importLocation) ||
resolveCallback(currentLocation, importLocation)
);
};
const ptr = zokrates.compile(source, location, callback, config, curve);
return Object.assign(
const ptr = pkg.compile(source, location, resolveCallback, config, curve);
const result = Object.assign(
{
program: ptr.program(),
abi: ptr.abi(),
},
snarkjs ? { snarkjs: { program: ptr.snarkjs_program() } } : {}
);
ptr.free();
return result;
},
computeWitness: (input, args, computeOptions = {}) => {
const { program, abi } =
input instanceof Uint8Array ? { program: input, abi: null } : input;
const { snarkjs = false } = computeOptions;
const ptr = zokrates.compute_witness(program, abi, JSON.stringify(args), {
const ptr = pkg.compute_witness(program, abi, JSON.stringify(args), {
snarkjs: snarkjs,
});
return Object.assign(
const result = Object.assign(
{
witness: ptr.witness(),
output: ptr.output(),
@ -82,28 +44,31 @@ module.exports = (dep) => {
}
: {}
);
ptr.free();
return result;
},
setup: (program, options) => {
return zokrates.setup(program, options);
return pkg.setup(program, options);
},
universalSetup: (curve, size) => {
return zokrates.universal_setup(curve, size);
return pkg.universal_setup(curve, size);
},
setupWithSrs: (srs, program, options) => {
return zokrates.setup_with_srs(srs, program, options);
return pkg.setup_with_srs(srs, program, options);
},
generateProof: (program, witness, provingKey, options) => {
return zokrates.generate_proof(program, witness, provingKey, options);
return pkg.generate_proof(program, witness, provingKey, options);
},
verify: (vk, proof) => {
return zokrates.verify(vk, proof);
verify: (vk, proof, options) => {
return pkg.verify(vk, proof, options);
},
exportSolidityVerifier: (vk) => {
return zokrates.export_solidity_verifier(vk);
return pkg.export_solidity_verifier(vk);
},
utils: {
formatProof: (proof) => {
return zokrates.format_proof(proof);
return pkg.format_proof(proof);
},
},
};
@ -125,16 +90,17 @@ module.exports = (dep) => {
defaultProvider.setupWithSrs(srs, program, options),
generateProof: (program, witness, provingKey) =>
defaultProvider.generateProof(program, witness, provingKey, options),
verify: (vk, proof) => defaultProvider.verify(vk, proof),
verify: (vk, proof) => defaultProvider.verify(vk, proof, options),
exportSolidityVerifier: (vk) =>
defaultProvider.exportSolidityVerifier(vk),
utils: {
formatProof: (proof) => defaultProvider.utils.formatProof(proof),
},
metadata: pkg.metadata,
};
};
return {
...withOptions({ scheme: "g16", curve: "bn128" }),
...withOptions({ backend: "ark", scheme: "g16", curve: "bn128" }),
};
};

View file

@ -1,12 +1,7 @@
const wrapper = require("../wrapper.js");
const stdlib = require("../stdlib.js");
const metadata = require("../metadata.js");
const lib = require("../lib.js");
const initialize = async () => {
return wrapper({
zokrates: require("./pkg/index.js"),
stdlib,
});
return lib(require("./pkg/index.js"));
};
module.exports = { initialize, metadata };
module.exports = { initialize };

File diff suppressed because it is too large Load diff

View file

@ -19,9 +19,7 @@
"pkg",
"index.js",
"index.d.ts",
"wrapper.js",
"stdlib.js",
"metadata.js"
"lib.js"
],
"types": "index.d.ts",
"exports": {
@ -30,33 +28,24 @@
},
"scripts": {
"wasm-pack": "wasm-pack build --out-name index",
"setup": "npm install && gulp setup",
"prebuild": "npm run setup",
"prebuild": "npm install",
"build": "npm run build:bundler && npm run build:node",
"prebuild:dev": "npm run setup",
"build:dev": "npm run build:bundler:dev && npm run build:node:dev",
"build:bundler": "rimraf pkg && npm run wasm-pack -- --target bundler --release && npm run clean-pkg",
"build:bundler:dev": "rimraf pkg && npm run wasm-pack -- --target bundler --dev && npm run clean-pkg",
"build:node": "rimraf node/pkg && npm run wasm-pack -- --target nodejs -d node/pkg --release && npm run clean-node-pkg",
"build:node:dev": "rimraf node/pkg && npm run wasm-pack -- --target nodejs -d node/pkg --dev && npm run clean-node-pkg",
"clean-pkg": "rimraf pkg/README.md pkg/.gitignore",
"clean-node-pkg": "rimraf node/pkg/README.md node/pkg/.gitignore",
"pretest": "npm run setup && npm run build:node:dev",
"clean-pkg": "rimraf pkg/README.md pkg/.gitignore pkg/package.json pkg/*.d.ts",
"clean-node-pkg": "rimraf node/pkg/README.md node/pkg/.gitignore node/pkg/package.json node/pkg/*.d.ts",
"pretest": "npm run build:node:dev",
"test": "npm run run-tests",
"run-tests": "mocha --timeout 100000 --require esm --recursive tests"
"run-tests": "mocha --timeout 100000 --recursive tests"
},
"devDependencies": {
"dree": "^2.6.1",
"esm": "^3.2.25",
"gulp": "^4.0.2",
"gulp-cli": "^2.3.0",
"mocha": "^9.2.0",
"rimraf": "^3.0.2",
"serve": "^11.3.2",
"snarkjs": "^0.4.19",
"text-encoding": "^0.7.0",
"toml": "^3.0.0",
"wasm-pack": "^0.10.2"
},
"dependencies": {}
}
}

View file

@ -1,8 +1,14 @@
mod util;
#[macro_use]
extern crate lazy_static;
use crate::util::normalize_path;
use serde::{Deserialize, Serialize};
use serde_json::to_string_pretty;
use std::convert::TryFrom;
use std::io::Cursor;
use std::path::PathBuf;
use std::io::{Cursor, Write};
use std::path::{Component, PathBuf};
use typed_arena::Arena;
use wasm_bindgen::prelude::*;
use zokrates_abi::{parse_strict, Decode, Encode, Inputs};
@ -11,8 +17,9 @@ use zokrates_ast::ir;
use zokrates_ast::ir::ProgEnum;
use zokrates_ast::typed::abi::Abi;
use zokrates_ast::typed::types::{ConcreteSignature, ConcreteType, GTupleType};
use zokrates_bellman::Bellman;
use zokrates_circom::{write_r1cs, write_witness};
use zokrates_common::helpers::{CurveParameter, SchemeParameter};
use zokrates_common::helpers::{BackendParameter, CurveParameter, SchemeParameter};
use zokrates_common::Resolver;
use zokrates_core::compile::{
compile as core_compile, CompilationArtifacts, CompileConfig, CompileError,
@ -26,6 +33,11 @@ use zokrates_proof_systems::{
UniversalBackend, UniversalScheme, GM17,
};
lazy_static! {
static ref STDLIB: serde_json::Value =
serde_json::from_str(include_str!(concat!(env!("OUT_DIR"), "/stdlib.json"))).unwrap();
}
#[wasm_bindgen]
pub struct CompilationResult {
program: Vec<u8>,
@ -99,32 +111,98 @@ impl<'a> Resolver<Error> for JsResolver<'a> {
current_location: PathBuf,
import_location: PathBuf,
) -> Result<(String, PathBuf), Error> {
let value = self
.callback
.call2(
&JsValue::UNDEFINED,
&current_location.to_str().unwrap().into(),
&import_location.to_str().unwrap().into(),
)
.map_err(|_| {
Error::new(format!(
"Could not resolve `{}`: error thrown in resolve callback",
import_location.display()
))
})?;
let base: PathBuf = match import_location.components().next() {
Some(Component::CurDir) | Some(Component::ParentDir) => {
current_location.parent().unwrap().into()
}
_ => PathBuf::default(),
};
if value.is_null() || value.is_undefined() {
Err(Error::new(format!(
"Could not resolve `{}`",
import_location.display()
)))
} else {
let result: ResolverResult = value.into_serde().unwrap();
Ok((result.source, PathBuf::from(result.location)))
let path = base.join(import_location.clone()).with_extension("zok");
match path.components().next() {
Some(Component::Normal(_)) => {
let path_normalized = normalize_path(path);
let source = STDLIB
.get(&path_normalized.to_str().unwrap())
.ok_or_else(|| {
Error::new(format!(
"module `{}` not found in stdlib",
import_location.display()
))
})?
.as_str()
.unwrap();
Ok((source.to_owned(), path_normalized))
}
_ => {
let value = self
.callback
.call2(
&JsValue::UNDEFINED,
&current_location.to_str().unwrap().into(),
&import_location.to_str().unwrap().into(),
)
.map_err(|_| {
Error::new(format!(
"could not resolve module `{}`",
import_location.display()
))
})?;
if value.is_null() || value.is_undefined() {
return Err(Error::new(format!(
"could not resolve module `{}`",
import_location.display()
)));
}
let result: serde_json::Value = value.into_serde().unwrap();
let source = result
.get("source")
.ok_or_else(|| Error::new("missing field `source`"))?
.as_str()
.ok_or_else(|| {
Error::new("invalid type for field `source`, should be a string")
})?;
let location = result
.get("location")
.ok_or_else(|| Error::new("missing field `location`"))?
.as_str()
.ok_or_else(|| {
Error::new("invalid type for field `location`, should be a string")
})?;
Ok((source.to_owned(), PathBuf::from(location.to_owned())))
}
}
}
}
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);
}
#[derive(Default)]
pub struct ConsoleWriter {
buf: Vec<u8>,
}
impl Write for ConsoleWriter {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.buf.write(buf)
}
fn flush(&mut self) -> std::io::Result<()> {
log(std::str::from_utf8(&self.buf.as_slice()[..self.buf.len() - 1]).unwrap());
self.buf.clear();
Ok(())
}
}
mod internal {
use super::*;
@ -223,8 +301,9 @@ mod internal {
let public_inputs = program.public_inputs();
let mut writer = ConsoleWriter::default();
let witness = interpreter
.execute(program, &inputs.encode())
.execute_with_log_stream(program, &inputs.encode(), &mut writer)
.map_err(|err| JsValue::from_str(&format!("Execution failed: {}", err)))?;
let return_values: serde_json::Value =
@ -388,6 +467,7 @@ pub fn export_solidity_verifier(vk: JsValue) -> Result<JsValue, JsValue> {
let vk: serde_json::Value = vk
.into_serde()
.map_err(|e| JsValue::from_str(&e.to_string()))?;
let curve = CurveParameter::try_from(
vk["curve"]
.as_str()
@ -419,6 +499,13 @@ pub fn export_solidity_verifier(vk: JsValue) -> Result<JsValue, JsValue> {
pub fn setup(program: &[u8], options: JsValue) -> Result<JsValue, JsValue> {
let options: serde_json::Value = options.into_serde().unwrap();
let backend = BackendParameter::try_from(
options["backend"]
.as_str()
.ok_or_else(|| JsValue::from_str("Invalid options: missing field `backend`"))?,
)
.map_err(|e| JsValue::from_str(&e))?;
let scheme = SchemeParameter::try_from(
options["scheme"]
.as_str()
@ -430,20 +517,26 @@ pub fn setup(program: &[u8], options: JsValue) -> Result<JsValue, JsValue> {
.map_err(|err| JsValue::from_str(&err))?
.collect();
match scheme {
SchemeParameter::G16 => match prog {
match (backend, scheme) {
(BackendParameter::Bellman, SchemeParameter::G16) => match prog {
ProgEnum::Bn128Program(p) => Ok(internal::setup_non_universal::<_, G16, Bellman>(p)),
_ => Err(JsValue::from_str(
"`bellman` backend only supports programs compiled with curve `bn128`",
)),
},
(BackendParameter::Ark, SchemeParameter::G16) => match prog {
ProgEnum::Bn128Program(p) => Ok(internal::setup_non_universal::<_, G16, Ark>(p)),
ProgEnum::Bls12_381Program(p) => Ok(internal::setup_non_universal::<_, G16, Ark>(p)),
ProgEnum::Bls12_377Program(p) => Ok(internal::setup_non_universal::<_, G16, Ark>(p)),
ProgEnum::Bw6_761Program(p) => Ok(internal::setup_non_universal::<_, G16, Ark>(p)),
},
SchemeParameter::GM17 => match prog {
(BackendParameter::Ark, SchemeParameter::GM17) => match prog {
ProgEnum::Bn128Program(p) => Ok(internal::setup_non_universal::<_, GM17, Ark>(p)),
ProgEnum::Bls12_381Program(p) => Ok(internal::setup_non_universal::<_, GM17, Ark>(p)),
ProgEnum::Bls12_377Program(p) => Ok(internal::setup_non_universal::<_, GM17, Ark>(p)),
ProgEnum::Bw6_761Program(p) => Ok(internal::setup_non_universal::<_, GM17, Ark>(p)),
},
_ => Err(JsValue::from_str("Unsupported scheme")),
_ => Err(JsValue::from_str("Unsupported options")),
}
}
@ -507,6 +600,13 @@ pub fn generate_proof(
) -> Result<JsValue, JsValue> {
let options: serde_json::Value = options.into_serde().unwrap();
let backend = BackendParameter::try_from(
options["backend"]
.as_str()
.ok_or_else(|| JsValue::from_str("Invalid options: missing field `backend`"))?,
)
.map_err(|e| JsValue::from_str(&e))?;
let scheme = SchemeParameter::try_from(
options["scheme"]
.as_str()
@ -518,8 +618,16 @@ pub fn generate_proof(
.map_err(|err| JsValue::from_str(&err))?
.collect();
match scheme {
SchemeParameter::G16 => match prog {
match (backend, scheme) {
(BackendParameter::Bellman, SchemeParameter::G16) => match prog {
ProgEnum::Bn128Program(p) => {
internal::generate_proof::<_, G16, Bellman>(p, witness, pk)
}
_ => Err(JsValue::from_str(
"`bellman` backend only supports programs compiled with curve `bn128`",
)),
},
(BackendParameter::Ark, SchemeParameter::G16) => match prog {
ProgEnum::Bn128Program(p) => internal::generate_proof::<_, G16, Ark>(p, witness, pk),
ProgEnum::Bls12_381Program(p) => {
internal::generate_proof::<_, G16, Ark>(p, witness, pk)
@ -529,7 +637,7 @@ pub fn generate_proof(
}
ProgEnum::Bw6_761Program(p) => internal::generate_proof::<_, G16, Ark>(p, witness, pk),
},
SchemeParameter::GM17 => match prog {
(BackendParameter::Ark, SchemeParameter::GM17) => match prog {
ProgEnum::Bn128Program(p) => internal::generate_proof::<_, GM17, Ark>(p, witness, pk),
ProgEnum::Bls12_381Program(p) => {
internal::generate_proof::<_, GM17, Ark>(p, witness, pk)
@ -539,7 +647,7 @@ pub fn generate_proof(
}
ProgEnum::Bw6_761Program(p) => internal::generate_proof::<_, GM17, Ark>(p, witness, pk),
},
SchemeParameter::MARLIN => match prog {
(BackendParameter::Ark, SchemeParameter::MARLIN) => match prog {
ProgEnum::Bn128Program(p) => internal::generate_proof::<_, Marlin, Ark>(p, witness, pk),
ProgEnum::Bls12_381Program(p) => {
internal::generate_proof::<_, Marlin, Ark>(p, witness, pk)
@ -551,11 +659,20 @@ pub fn generate_proof(
internal::generate_proof::<_, Marlin, Ark>(p, witness, pk)
}
},
_ => Err(JsValue::from_str("Unsupported options")),
}
}
#[wasm_bindgen]
pub fn verify(vk: JsValue, proof: JsValue) -> Result<JsValue, JsValue> {
pub fn verify(vk: JsValue, proof: JsValue, options: JsValue) -> Result<JsValue, JsValue> {
let options: serde_json::Value = options.into_serde().unwrap();
let backend = BackendParameter::try_from(
options["backend"]
.as_str()
.ok_or_else(|| JsValue::from_str("Invalid options: missing field `backend`"))?,
)
.map_err(|e| JsValue::from_str(&e))?;
let vk: serde_json::Value = vk.into_serde().unwrap();
let proof: serde_json::Value = proof.into_serde().unwrap();
let vk_curve = CurveParameter::try_from(
@ -600,25 +717,32 @@ pub fn verify(vk: JsValue, proof: JsValue) -> Result<JsValue, JsValue> {
let scheme = vk_scheme;
let curve = vk_curve;
match scheme {
SchemeParameter::G16 => match curve {
match (backend, scheme) {
(BackendParameter::Bellman, SchemeParameter::G16) => match curve {
CurveParameter::Bn128 => internal::verify::<Bn128Field, G16, Bellman>(vk, proof),
_ => Err(JsValue::from_str(
"`bellman` backend only supports curve `bn128`",
)),
},
(BackendParameter::Ark, SchemeParameter::G16) => match curve {
CurveParameter::Bn128 => internal::verify::<Bn128Field, G16, Ark>(vk, proof),
CurveParameter::Bls12_381 => internal::verify::<Bls12_381Field, G16, Ark>(vk, proof),
CurveParameter::Bls12_377 => internal::verify::<Bls12_377Field, G16, Ark>(vk, proof),
CurveParameter::Bw6_761 => internal::verify::<Bw6_761Field, G16, Ark>(vk, proof),
},
SchemeParameter::GM17 => match curve {
(BackendParameter::Ark, SchemeParameter::GM17) => match curve {
CurveParameter::Bn128 => internal::verify::<Bn128Field, GM17, Ark>(vk, proof),
CurveParameter::Bls12_381 => internal::verify::<Bls12_381Field, GM17, Ark>(vk, proof),
CurveParameter::Bls12_377 => internal::verify::<Bls12_377Field, GM17, Ark>(vk, proof),
CurveParameter::Bw6_761 => internal::verify::<Bw6_761Field, GM17, Ark>(vk, proof),
},
SchemeParameter::MARLIN => match curve {
(BackendParameter::Ark, SchemeParameter::MARLIN) => match curve {
CurveParameter::Bn128 => internal::verify::<Bn128Field, Marlin, Ark>(vk, proof),
CurveParameter::Bls12_381 => internal::verify::<Bls12_381Field, Marlin, Ark>(vk, proof),
CurveParameter::Bls12_377 => internal::verify::<Bls12_377Field, Marlin, Ark>(vk, proof),
CurveParameter::Bw6_761 => internal::verify::<Bw6_761Field, Marlin, Ark>(vk, proof),
},
_ => Err(JsValue::from_str("Unsupported options")),
}
}
@ -654,6 +778,13 @@ pub fn format_proof(proof: JsValue) -> Result<JsValue, JsValue> {
}
}
#[wasm_bindgen]
pub fn metadata() -> JsValue {
let value: serde_json::Value =
serde_json::from_str(include_str!(concat!(env!("OUT_DIR"), "/metadata.json"))).unwrap();
JsValue::from_serde(&value).unwrap()
}
#[wasm_bindgen(start)]
pub fn main_js() -> Result<(), JsValue> {
std::panic::set_hook(Box::new(console_error_panic_hook::hook));

28
zokrates_js/src/util.rs Normal file
View file

@ -0,0 +1,28 @@
use std::path::{Component, PathBuf};
pub fn normalize_path(path: PathBuf) -> PathBuf {
let mut components = path.components().peekable();
let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() {
components.next();
PathBuf::from(c.as_os_str())
} else {
PathBuf::new()
};
for component in components {
match component {
Component::Prefix(..) => unreachable!(),
Component::RootDir => {
ret.push(component.as_os_str());
}
Component::CurDir => {}
Component::ParentDir => {
ret.pop();
}
Component::Normal(c) => {
ret.push(c);
}
}
}
ret
}

View file

@ -14,9 +14,11 @@ describe("tests", () => {
before(() => {
return initialize().then((defaultProvider) => {
zokratesProvider = defaultProvider;
return fs.promises.mkdtemp(path.join(os.tmpdir(), path.sep)).then((folder) => {
tmpFolder = folder;
});
return fs.promises
.mkdtemp(path.join(os.tmpdir(), path.sep))
.then((folder) => {
tmpFolder = folder;
});
});
});
@ -24,14 +26,21 @@ describe("tests", () => {
if (globalThis.curve_bn128) globalThis.curve_bn128.terminate();
});
describe("metadata", () => {
it("call", () => {
let metadata = zokratesProvider.metadata();
assert.ok(metadata);
assert.ok(metadata.version !== undefined);
});
});
describe("compilation", () => {
it("should compile", () => {
assert.doesNotThrow(() => {
const artifacts = zokratesProvider.compile(
"def main() -> field { return 42; }"
);
assert.ok(artifacts !== undefined);
assert.ok(artifacts);
assert.ok(artifacts.snarkjs === undefined);
});
});
@ -42,7 +51,7 @@ describe("tests", () => {
"def main() -> field { return 42; }",
{ snarkjs: true }
);
assert.ok(artifacts !== undefined);
assert.ok(artifacts);
assert.ok(artifacts.snarkjs.program !== undefined);
});
});
@ -52,11 +61,8 @@ describe("tests", () => {
});
it("should resolve stdlib module", () => {
const stdlib = require("../stdlib.js");
assert.doesNotThrow(() => {
const code = `import "${
Object.keys(stdlib)[0]
}" as func;\ndef main() { return; }`;
const code = `import "utils/pack/bool/unpack" as unpack;\ndef main() { return; }`;
zokratesProvider.compile(code);
});
});
@ -64,7 +70,7 @@ describe("tests", () => {
it("should resolve user module", () => {
assert.doesNotThrow(() => {
const code =
'import "test" as test;\ndef main() -> field { return test(); }';
'import "./test" as test;\ndef main() -> field { return test(); }';
const options = {
resolveCallback: (_, path) => {
return {
@ -80,7 +86,7 @@ describe("tests", () => {
it("should throw on unresolved module", () => {
assert.throws(() => {
const code =
'import "test" as test;\ndef main() -> field { return test(); }';
'import "./test" as test;\ndef main() -> field { return test(); }';
zokratesProvider.compile(code);
});
});
@ -224,13 +230,24 @@ describe("tests", () => {
});
};
for (const scheme of ["g16", "gm17", "marlin"]) {
describe(scheme, () => {
for (const curve of ["bn128", "bls12_381", "bls12_377", "bw6_761"]) {
describe(curve, () => runWithOptions({ scheme, curve }));
}
describe("ark", () => {
for (const scheme of ["g16", "gm17", "marlin"]) {
describe(scheme, () => {
for (const curve of ["bn128", "bls12_381", "bls12_377", "bw6_761"]) {
describe(curve, () =>
runWithOptions({ backend: "ark", scheme, curve })
);
}
});
}
});
describe("bellman", () => {
describe("g16", () => {
describe("bn128", () =>
runWithOptions({ backend: "bellman", scheme: "g16", curve: "bn128" }));
});
}
});
const testRunner = (rootPath, testPath, test) => {
let entryPoint;