refactor zokrates-js, add backend option
This commit is contained in:
parent
2a9e619250
commit
4b83ebc79f
15 changed files with 424 additions and 8118 deletions
11
Cargo.lock
generated
11
Cargo.lock
generated
|
@ -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",
|
||||
|
|
|
@ -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`
|
||||
|
||||
|
|
|
@ -106,6 +106,8 @@ impl Interpreter {
|
|||
}
|
||||
|
||||
writeln!(log_stream).map_err(|_| Error::LogStream)?;
|
||||
|
||||
log_stream.flush().map_err(|_| Error::LogStream)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
45
zokrates_js/build.rs
Normal 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();
|
||||
}
|
|
@ -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"));
|
5
zokrates_js/index.d.ts
vendored
5
zokrates_js/index.d.ts
vendored
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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" }),
|
||||
};
|
||||
};
|
|
@ -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 };
|
||||
|
|
7998
zokrates_js/package-lock.json
generated
7998
zokrates_js/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -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": {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
¤t_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,
|
||||
¤t_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
28
zokrates_js/src/util.rs
Normal 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
|
||||
}
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue