Merge branch 'develop' into optimize-zir-solver
This commit is contained in:
commit
6f61a93855
74 changed files with 9409 additions and 1594 deletions
|
@ -76,6 +76,9 @@ jobs:
|
|||
command: rustc --version; cargo --version; rustup --version
|
||||
- setup-sccache
|
||||
- restore-sccache-cache
|
||||
- run:
|
||||
name: Install foundry
|
||||
command: ./scripts/install_foundry.sh
|
||||
- run:
|
||||
name: Run integration tests
|
||||
no_output_timeout: "30m"
|
||||
|
@ -119,11 +122,13 @@ jobs:
|
|||
- setup-sccache
|
||||
- restore-sccache-cache
|
||||
- run:
|
||||
name: Check format
|
||||
command: cargo fmt --all -- --check
|
||||
- run:
|
||||
name: Run clippy
|
||||
command: cargo clippy -- -D warnings
|
||||
name: Install headless chrome dependencies
|
||||
command: |
|
||||
apt-get update && apt-get install -yq \
|
||||
ca-certificates fonts-liberation libasound2 libatk-bridge2.0-0 libatk1.0-0 libc6 libcairo2 libcups2 \
|
||||
libdbus-1-3 libexpat1 libfontconfig1 libgbm1 libgcc1 libglib2.0-0 libgtk-3-0 libnspr4 libnss3 \
|
||||
libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 \
|
||||
libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 lsb-release wget xdg-utils
|
||||
- run:
|
||||
name: Run tests
|
||||
no_output_timeout: "30m"
|
||||
|
@ -244,7 +249,7 @@ workflows:
|
|||
jobs:
|
||||
- build
|
||||
- test
|
||||
- wasm_test
|
||||
# - wasm_test
|
||||
- integration_test
|
||||
- zokrates_js_build
|
||||
- zokrates_js_test
|
||||
|
@ -302,7 +307,7 @@ workflows:
|
|||
requires:
|
||||
- build
|
||||
- test
|
||||
- wasm_test
|
||||
# - wasm_test
|
||||
- integration_test
|
||||
- zokrates_js_build
|
||||
- zokrates_js_test
|
||||
|
|
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -4,6 +4,22 @@ All notable changes to this project will be documented in this file.
|
|||
## [Unreleased]
|
||||
https://github.com/Zokrates/ZoKrates/compare/latest...develop
|
||||
|
||||
## [0.8.4] - 2023-01-31
|
||||
|
||||
### Release
|
||||
- https://github.com/Zokrates/ZoKrates/releases/tag/0.8.4 <!-- markdown-link-check-disable-line -->
|
||||
|
||||
### Changes
|
||||
- Fix array propagation for spreads and repeaters (#1269, @schaeff)
|
||||
- Remove solc dependency for tests, use foundry instead (#1266, @schaeff)
|
||||
- Optimize `zokrates-js` library size (#1264, @dark64)
|
||||
- Use multicore feature in ark and bellman to improve performance (#1261, @dark64)
|
||||
- Allow user-provided randomness in setup and proof generation (#1254, @dark64)
|
||||
- Fix typos (#1260, @rex4539)
|
||||
- Introduce constraint generation through assembly blocks (#1246, @dark64)
|
||||
- Loosen up whitespace restrictions to allow more formatting styles (#1232, @dark64)
|
||||
- Reduce cost of boolean array equality checks (#1228, @schaeff)
|
||||
|
||||
## [0.8.3] - 2022-10-11
|
||||
|
||||
### Release
|
||||
|
|
602
Cargo.lock
generated
602
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,5 @@
|
|||
[workspace]
|
||||
|
||||
resolver = "2"
|
||||
members = [
|
||||
"zokrates_common",
|
||||
"zokrates_core",
|
||||
|
@ -12,7 +12,6 @@ members = [
|
|||
"zokrates_abi",
|
||||
"zokrates_test",
|
||||
"zokrates_core_test",
|
||||
"zokrates_solidity_test",
|
||||
"zokrates_ark",
|
||||
"zokrates_ast",
|
||||
"zokrates_interpreter",
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Reduce cost of boolean array equality checks
|
|
@ -1 +0,0 @@
|
|||
Loosen up whitespace restrictions to allow more formatting styles
|
|
@ -1 +0,0 @@
|
|||
Introduce constraint generation through assembly blocks
|
|
@ -1 +0,0 @@
|
|||
Fix typos
|
1
changelogs/unreleased/1275-dark64
Normal file
1
changelogs/unreleased/1275-dark64
Normal file
|
@ -0,0 +1 @@
|
|||
Show help when running `zokrates mpc`
|
|
@ -1,11 +1,9 @@
|
|||
FROM rustlang/rust:nightly
|
||||
|
||||
MAINTAINER JacobEberhardt <jacob.eberhardt@tu-berlin.de>, Thibaut Schaeffer <thibaut@schaeff.fr>
|
||||
|
||||
RUN useradd -u 1000 -m zokrates
|
||||
|
||||
COPY ./scripts/install_solcjs_deb.sh /tmp/
|
||||
RUN /tmp/install_solcjs_deb.sh
|
||||
COPY ./scripts/install_foundry_deb.sh /tmp/
|
||||
RUN /tmp/install_foundry_deb.sh
|
||||
|
||||
USER zokrates
|
||||
|
||||
|
|
|
@ -2,5 +2,4 @@
|
|||
|
||||
# Exit if any subcommand fails
|
||||
set -e
|
||||
|
||||
cargo test -j 4 --release --package zokrates_cli -- --ignored
|
6
scripts/install_foundry.sh
Executable file
6
scripts/install_foundry.sh
Executable file
|
@ -0,0 +1,6 @@
|
|||
#!/bin/bash
|
||||
|
||||
apt-get update -y
|
||||
apt-get install -y curl gnupg sudo build-essential git
|
||||
curl -L https://foundry.paradigm.xyz | bash
|
||||
$HOME/.foundry/bin/foundryup
|
|
@ -1,7 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
apt-get update -y
|
||||
apt-get install -y curl gnupg sudo build-essential git
|
||||
curl -sL https://deb.nodesource.com/setup_16.x | bash -
|
||||
apt-get install -y nodejs
|
||||
npm i -g solc
|
|
@ -1,9 +1,20 @@
|
|||
[package]
|
||||
name = "zokrates_ark"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[features]
|
||||
default = []
|
||||
multicore = [
|
||||
"ark-ff/parallel",
|
||||
"ark-ec/parallel",
|
||||
"ark-groth16/parallel",
|
||||
"ark-gm17/parallel",
|
||||
"ark-marlin/parallel",
|
||||
"ark-poly/parallel",
|
||||
"ark-poly-commit/parallel",
|
||||
"ark-crypto-primitives/parallel",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
zokrates_field = { version = "0.5", path = "../zokrates_field", default-features = false }
|
||||
|
|
|
@ -9,19 +9,18 @@ use zokrates_field::{ArkFieldExtensions, Field};
|
|||
use crate::Computation;
|
||||
use crate::{parse_fr, parse_g1, parse_g2};
|
||||
use crate::{serialization, Ark};
|
||||
use rand_0_8::{rngs::StdRng, SeedableRng};
|
||||
use rand_0_8::{CryptoRng, RngCore};
|
||||
use zokrates_ast::ir::{ProgIterator, Statement, Witness};
|
||||
use zokrates_proof_systems::gm17::{ProofPoints, VerificationKey, GM17};
|
||||
use zokrates_proof_systems::Scheme;
|
||||
use zokrates_proof_systems::{Backend, NonUniversalBackend, Proof, SetupKeypair};
|
||||
|
||||
impl<T: Field + ArkFieldExtensions> NonUniversalBackend<T, GM17> for Ark {
|
||||
fn setup<'a, I: IntoIterator<Item = Statement<'a, T>>>(
|
||||
fn setup<'a, I: IntoIterator<Item = Statement<'a, T>>, R: RngCore + CryptoRng>(
|
||||
program: ProgIterator<'a, T, I>,
|
||||
rng: &mut R,
|
||||
) -> SetupKeypair<T, GM17> {
|
||||
let computation = Computation::without_witness(program);
|
||||
|
||||
let rng = &mut StdRng::from_entropy();
|
||||
let (pk, vk) = ArkGM17::<T::ArkEngine>::circuit_specific_setup(computation, rng).unwrap();
|
||||
|
||||
let mut pk_vec: Vec<u8> = Vec::new();
|
||||
|
@ -41,10 +40,11 @@ impl<T: Field + ArkFieldExtensions> NonUniversalBackend<T, GM17> for Ark {
|
|||
}
|
||||
|
||||
impl<T: Field + ArkFieldExtensions> Backend<T, GM17> for Ark {
|
||||
fn generate_proof<'a, I: IntoIterator<Item = Statement<'a, T>>>(
|
||||
fn generate_proof<'a, I: IntoIterator<Item = Statement<'a, T>>, R: RngCore + CryptoRng>(
|
||||
program: ProgIterator<'a, T, I>,
|
||||
witness: Witness<T>,
|
||||
proving_key: Vec<u8>,
|
||||
rng: &mut R,
|
||||
) -> Proof<T, GM17> {
|
||||
let computation = Computation::with_witness(program, witness);
|
||||
|
||||
|
@ -59,9 +59,7 @@ impl<T: Field + ArkFieldExtensions> Backend<T, GM17> for Ark {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let rng = &mut StdRng::from_entropy();
|
||||
let proof = ArkGM17::<T::ArkEngine>::prove(&pk, computation, rng).unwrap();
|
||||
|
||||
let proof_points = ProofPoints {
|
||||
a: parse_g1::<T>(&proof.a),
|
||||
b: parse_g2::<T>(&proof.b),
|
||||
|
@ -110,6 +108,8 @@ impl<T: Field + ArkFieldExtensions> Backend<T, GM17> for Ark {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rand_0_8::rngs::StdRng;
|
||||
use rand_0_8::SeedableRng;
|
||||
use zokrates_ast::flat::{Parameter, Variable};
|
||||
use zokrates_ast::ir::{Prog, Statement};
|
||||
use zokrates_interpreter::Interpreter;
|
||||
|
@ -125,15 +125,18 @@ mod tests {
|
|||
statements: vec![Statement::constraint(Variable::new(0), Variable::public(0))],
|
||||
};
|
||||
|
||||
let keypair = <Ark as NonUniversalBackend<Bls12_377Field, GM17>>::setup(program.clone());
|
||||
let rng = &mut StdRng::from_entropy();
|
||||
let keypair =
|
||||
<Ark as NonUniversalBackend<Bls12_377Field, GM17>>::setup(program.clone(), rng);
|
||||
let interpreter = Interpreter::default();
|
||||
|
||||
let witness = interpreter
|
||||
.execute(program.clone(), &[Bls12_377Field::from(42)])
|
||||
.unwrap();
|
||||
|
||||
let proof =
|
||||
<Ark as Backend<Bls12_377Field, GM17>>::generate_proof(program, witness, keypair.pk);
|
||||
let proof = <Ark as Backend<Bls12_377Field, GM17>>::generate_proof(
|
||||
program, witness, keypair.pk, rng,
|
||||
);
|
||||
let ans = <Ark as Backend<Bls12_377Field, GM17>>::verify(keypair.vk, proof);
|
||||
|
||||
assert!(ans);
|
||||
|
@ -147,7 +150,8 @@ mod tests {
|
|||
statements: vec![Statement::constraint(Variable::new(0), Variable::public(0))],
|
||||
};
|
||||
|
||||
let keypair = <Ark as NonUniversalBackend<Bw6_761Field, GM17>>::setup(program.clone());
|
||||
let rng = &mut StdRng::from_entropy();
|
||||
let keypair = <Ark as NonUniversalBackend<Bw6_761Field, GM17>>::setup(program.clone(), rng);
|
||||
let interpreter = Interpreter::default();
|
||||
|
||||
let witness = interpreter
|
||||
|
@ -155,7 +159,7 @@ mod tests {
|
|||
.unwrap();
|
||||
|
||||
let proof =
|
||||
<Ark as Backend<Bw6_761Field, GM17>>::generate_proof(program, witness, keypair.pk);
|
||||
<Ark as Backend<Bw6_761Field, GM17>>::generate_proof(program, witness, keypair.pk, rng);
|
||||
let ans = <Ark as Backend<Bw6_761Field, GM17>>::verify(keypair.vk, proof);
|
||||
|
||||
assert!(ans);
|
||||
|
|
|
@ -11,21 +11,18 @@ use zokrates_proof_systems::{Backend, NonUniversalBackend, Proof, SetupKeypair};
|
|||
use crate::Computation;
|
||||
use crate::{parse_fr, serialization, Ark};
|
||||
use crate::{parse_g1, parse_g2};
|
||||
use rand_0_8::{rngs::StdRng, SeedableRng};
|
||||
use rand_0_8::{CryptoRng, RngCore};
|
||||
use zokrates_ast::ir::{ProgIterator, Statement, Witness};
|
||||
use zokrates_proof_systems::groth16::{ProofPoints, VerificationKey, G16};
|
||||
use zokrates_proof_systems::Scheme;
|
||||
|
||||
const G16_WARNING: &str = "WARNING: You are using the G16 scheme which is subject to malleability. See zokrates.github.io/toolbox/proving_schemes.html#g16-malleability for implications.";
|
||||
|
||||
impl<T: Field + ArkFieldExtensions> Backend<T, G16> for Ark {
|
||||
fn generate_proof<'a, I: IntoIterator<Item = Statement<'a, T>>>(
|
||||
fn generate_proof<'a, I: IntoIterator<Item = Statement<'a, T>>, R: RngCore + CryptoRng>(
|
||||
program: ProgIterator<'a, T, I>,
|
||||
witness: Witness<T>,
|
||||
proving_key: Vec<u8>,
|
||||
rng: &mut R,
|
||||
) -> Proof<T, G16> {
|
||||
println!("{}", G16_WARNING);
|
||||
|
||||
let computation = Computation::with_witness(program, witness);
|
||||
|
||||
let inputs = computation
|
||||
|
@ -39,9 +36,7 @@ impl<T: Field + ArkFieldExtensions> Backend<T, G16> for Ark {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let rng = &mut StdRng::from_entropy();
|
||||
let proof = Groth16::<T::ArkEngine>::prove(&pk, computation, rng).unwrap();
|
||||
|
||||
let proof_points = ProofPoints {
|
||||
a: parse_g1::<T>(&proof.a),
|
||||
b: parse_g2::<T>(&proof.b),
|
||||
|
@ -86,14 +81,11 @@ impl<T: Field + ArkFieldExtensions> Backend<T, G16> for Ark {
|
|||
}
|
||||
|
||||
impl<T: Field + ArkFieldExtensions> NonUniversalBackend<T, G16> for Ark {
|
||||
fn setup<'a, I: IntoIterator<Item = Statement<'a, T>>>(
|
||||
fn setup<'a, I: IntoIterator<Item = Statement<'a, T>>, R: RngCore + CryptoRng>(
|
||||
program: ProgIterator<'a, T, I>,
|
||||
rng: &mut R,
|
||||
) -> SetupKeypair<T, G16> {
|
||||
println!("{}", G16_WARNING);
|
||||
|
||||
let computation = Computation::without_witness(program);
|
||||
|
||||
let rng = &mut StdRng::from_entropy();
|
||||
let (pk, vk) = Groth16::<T::ArkEngine>::circuit_specific_setup(computation, rng).unwrap();
|
||||
|
||||
let mut pk_vec: Vec<u8> = Vec::new();
|
||||
|
@ -113,6 +105,8 @@ impl<T: Field + ArkFieldExtensions> NonUniversalBackend<T, G16> for Ark {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rand_0_8::rngs::StdRng;
|
||||
use rand_0_8::SeedableRng;
|
||||
use zokrates_ast::flat::{Parameter, Variable};
|
||||
use zokrates_ast::ir::{Prog, Statement};
|
||||
use zokrates_interpreter::Interpreter;
|
||||
|
@ -128,15 +122,18 @@ mod tests {
|
|||
statements: vec![Statement::constraint(Variable::new(0), Variable::public(0))],
|
||||
};
|
||||
|
||||
let keypair = <Ark as NonUniversalBackend<Bls12_377Field, G16>>::setup(program.clone());
|
||||
let rng = &mut StdRng::from_entropy();
|
||||
let keypair =
|
||||
<Ark as NonUniversalBackend<Bls12_377Field, G16>>::setup(program.clone(), rng);
|
||||
let interpreter = Interpreter::default();
|
||||
|
||||
let witness = interpreter
|
||||
.execute(program.clone(), &[Bls12_377Field::from(42)])
|
||||
.unwrap();
|
||||
|
||||
let proof =
|
||||
<Ark as Backend<Bls12_377Field, G16>>::generate_proof(program, witness, keypair.pk);
|
||||
let proof = <Ark as Backend<Bls12_377Field, G16>>::generate_proof(
|
||||
program, witness, keypair.pk, rng,
|
||||
);
|
||||
let ans = <Ark as Backend<Bls12_377Field, G16>>::verify(keypair.vk, proof);
|
||||
|
||||
assert!(ans);
|
||||
|
@ -150,7 +147,8 @@ mod tests {
|
|||
statements: vec![Statement::constraint(Variable::new(0), Variable::public(0))],
|
||||
};
|
||||
|
||||
let keypair = <Ark as NonUniversalBackend<Bw6_761Field, G16>>::setup(program.clone());
|
||||
let rng = &mut StdRng::from_entropy();
|
||||
let keypair = <Ark as NonUniversalBackend<Bw6_761Field, G16>>::setup(program.clone(), rng);
|
||||
let interpreter = Interpreter::default();
|
||||
|
||||
let witness = interpreter
|
||||
|
@ -158,7 +156,7 @@ mod tests {
|
|||
.unwrap();
|
||||
|
||||
let proof =
|
||||
<Ark as Backend<Bw6_761Field, G16>>::generate_proof(program, witness, keypair.pk);
|
||||
<Ark as Backend<Bw6_761Field, G16>>::generate_proof(program, witness, keypair.pk, rng);
|
||||
let ans = <Ark as Backend<Bw6_761Field, G16>>::verify(keypair.vk, proof);
|
||||
|
||||
assert!(ans);
|
||||
|
|
|
@ -17,7 +17,7 @@ use ark_poly_commit::{
|
|||
};
|
||||
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
|
||||
use digest::Digest;
|
||||
use rand_0_8::{Error, RngCore, SeedableRng};
|
||||
use rand_0_8::{CryptoRng, Error, RngCore, SeedableRng};
|
||||
use sha3::Keccak256;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
|
@ -116,9 +116,7 @@ type MarlinInst<T> = ArkMarlin<
|
|||
>;
|
||||
|
||||
impl<T: Field + ArkFieldExtensions> UniversalBackend<T, marlin::Marlin> for Ark {
|
||||
fn universal_setup(size: u32) -> Vec<u8> {
|
||||
let rng = &mut rand_0_8::rngs::StdRng::from_entropy();
|
||||
|
||||
fn universal_setup<R: RngCore + CryptoRng>(size: u32, rng: &mut R) -> Vec<u8> {
|
||||
let srs = MarlinInst::<T>::universal_setup(
|
||||
2usize.pow(size),
|
||||
2usize.pow(size),
|
||||
|
@ -128,9 +126,7 @@ impl<T: Field + ArkFieldExtensions> UniversalBackend<T, marlin::Marlin> for Ark
|
|||
.unwrap();
|
||||
|
||||
let mut res = vec![];
|
||||
|
||||
srs.serialize(&mut res).unwrap();
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
|
@ -210,15 +206,14 @@ impl<T: Field + ArkFieldExtensions> UniversalBackend<T, marlin::Marlin> for Ark
|
|||
}
|
||||
|
||||
impl<T: Field + ArkFieldExtensions> Backend<T, marlin::Marlin> for Ark {
|
||||
fn generate_proof<'a, I: IntoIterator<Item = Statement<'a, T>>>(
|
||||
fn generate_proof<'a, I: IntoIterator<Item = Statement<'a, T>>, R: RngCore + CryptoRng>(
|
||||
program: ProgIterator<'a, T, I>,
|
||||
witness: Witness<T>,
|
||||
proving_key: Vec<u8>,
|
||||
rng: &mut R,
|
||||
) -> Proof<T, marlin::Marlin> {
|
||||
let computation = Computation::with_witness(program, witness);
|
||||
|
||||
let rng = &mut rand_0_8::rngs::StdRng::from_entropy();
|
||||
|
||||
let pk = IndexProverKey::<
|
||||
<<T as ArkFieldExtensions>::ArkEngine as PairingEngine>::Fr,
|
||||
MarlinKZG10<
|
||||
|
@ -229,7 +224,6 @@ impl<T: Field + ArkFieldExtensions> Backend<T, marlin::Marlin> for Ark {
|
|||
.unwrap();
|
||||
|
||||
let public_inputs = computation.public_inputs_values();
|
||||
|
||||
let inputs = public_inputs.iter().map(parse_fr::<T>).collect::<Vec<_>>();
|
||||
|
||||
let proof = MarlinInst::<T>::prove(&pk, computation, rng).unwrap();
|
||||
|
@ -386,6 +380,7 @@ impl<T: Field + ArkFieldExtensions> Backend<T, marlin::Marlin> for Ark {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rand_0_8::rngs::StdRng;
|
||||
use zokrates_ast::flat::{Parameter, Variable};
|
||||
use zokrates_ast::ir::{Prog, QuadComb, Statement};
|
||||
use zokrates_interpreter::Interpreter;
|
||||
|
@ -411,7 +406,8 @@ mod tests {
|
|||
],
|
||||
};
|
||||
|
||||
let srs = <Ark as UniversalBackend<Bls12_377Field, Marlin>>::universal_setup(5);
|
||||
let rng = &mut StdRng::from_entropy();
|
||||
let srs = <Ark as UniversalBackend<Bls12_377Field, Marlin>>::universal_setup(5, rng);
|
||||
let keypair =
|
||||
<Ark as UniversalBackend<Bls12_377Field, Marlin>>::setup(srs, program.clone()).unwrap();
|
||||
let interpreter = Interpreter::default();
|
||||
|
@ -420,8 +416,9 @@ mod tests {
|
|||
.execute(program.clone(), &[Bls12_377Field::from(42)])
|
||||
.unwrap();
|
||||
|
||||
let proof =
|
||||
<Ark as Backend<Bls12_377Field, Marlin>>::generate_proof(program, witness, keypair.pk);
|
||||
let proof = <Ark as Backend<Bls12_377Field, Marlin>>::generate_proof(
|
||||
program, witness, keypair.pk, rng,
|
||||
);
|
||||
let ans = <Ark as Backend<Bls12_377Field, Marlin>>::verify(keypair.vk, proof);
|
||||
|
||||
assert!(ans);
|
||||
|
@ -444,7 +441,8 @@ mod tests {
|
|||
],
|
||||
};
|
||||
|
||||
let srs = <Ark as UniversalBackend<Bw6_761Field, Marlin>>::universal_setup(5);
|
||||
let rng = &mut StdRng::from_entropy();
|
||||
let srs = <Ark as UniversalBackend<Bw6_761Field, Marlin>>::universal_setup(5, rng);
|
||||
let keypair =
|
||||
<Ark as UniversalBackend<Bw6_761Field, Marlin>>::setup(srs, program.clone()).unwrap();
|
||||
let interpreter = Interpreter::default();
|
||||
|
@ -453,8 +451,9 @@ mod tests {
|
|||
.execute(program.clone(), &[Bw6_761Field::from(42)])
|
||||
.unwrap();
|
||||
|
||||
let proof =
|
||||
<Ark as Backend<Bw6_761Field, Marlin>>::generate_proof(program, witness, keypair.pk);
|
||||
let proof = <Ark as Backend<Bw6_761Field, Marlin>>::generate_proof(
|
||||
program, witness, keypair.pk, rng,
|
||||
);
|
||||
let ans = <Ark as Backend<Bw6_761Field, Marlin>>::verify(keypair.vk, proof);
|
||||
|
||||
assert!(ans);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_ast"
|
||||
version = "0.1.3"
|
||||
version = "0.1.4"
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
|
|
|
@ -2664,7 +2664,7 @@ impl<'ast, T: Field> Constant for ArrayExpression<'ast, T> {
|
|||
e: TypedExpressionOrSpread<T>,
|
||||
) -> Vec<TypedExpression<T>> {
|
||||
match e {
|
||||
TypedExpressionOrSpread::Expression(e) => vec![e],
|
||||
TypedExpressionOrSpread::Expression(e) => vec![e.into_canonical_constant()],
|
||||
TypedExpressionOrSpread::Spread(s) => match s.array.into_inner() {
|
||||
ArrayExpressionInner::Value(v) => v
|
||||
.into_iter()
|
||||
|
@ -2698,7 +2698,7 @@ impl<'ast, T: Field> Constant for ArrayExpression<'ast, T> {
|
|||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
vec![e; count as usize]
|
||||
vec![e.into_canonical_constant(); count as usize]
|
||||
}
|
||||
a => unreachable!("{}", a),
|
||||
},
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
[package]
|
||||
name = "zokrates_bellman"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
wasm = ["bellman/nolog", "bellman/wasm"]
|
||||
multicore = ["bellman/multicore", "phase2/multicore"]
|
||||
|
||||
|
@ -15,8 +16,9 @@ zokrates_proof_systems = { version = "0.1", path = "../zokrates_proof_systems",
|
|||
bellman = { package = "bellman_ce", version = "^0.3", default-features = false }
|
||||
pairing = { package = "pairing_ce", version = "^0.21" }
|
||||
phase2 = { git = "https://github.com/Zokrates/phase2", default-features = false }
|
||||
rand_0_4 = { version = "0.4", package = "rand" }#
|
||||
getrandom = { version = "0.2", features = ["js", "wasm-bindgen"] }
|
||||
rand_0_4 = { version = "0.4", package = "rand" }
|
||||
rand_0_8 = { version = "0.8", package = "rand" }
|
||||
getrandom = { version = "0.2.8" }
|
||||
hex = "0.4.2"
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -8,26 +8,24 @@ use zokrates_field::BellmanFieldExtensions;
|
|||
use zokrates_field::Field;
|
||||
use zokrates_proof_systems::{Backend, MpcBackend, NonUniversalBackend, Proof, SetupKeypair};
|
||||
|
||||
use crate::Bellman;
|
||||
use crate::Computation;
|
||||
use crate::{get_random_seed, Bellman};
|
||||
use crate::{parse_g1, parse_g2};
|
||||
use phase2::MPCParameters;
|
||||
use rand_0_4::Rng;
|
||||
use rand_0_4::{ChaChaRng, SeedableRng};
|
||||
use rand_0_8::{CryptoRng, RngCore};
|
||||
use std::io::{Read, Write};
|
||||
use zokrates_ast::ir::{ProgIterator, Statement, Witness};
|
||||
use zokrates_proof_systems::groth16::{ProofPoints, VerificationKey, G16};
|
||||
use zokrates_proof_systems::Scheme;
|
||||
|
||||
const G16_WARNING: &str = "WARNING: You are using the G16 scheme which is subject to malleability. See zokrates.github.io/toolbox/proving_schemes.html#g16-malleability for implications.";
|
||||
|
||||
impl<T: Field + BellmanFieldExtensions> Backend<T, G16> for Bellman {
|
||||
fn generate_proof<'a, I: IntoIterator<Item = Statement<'a, T>>>(
|
||||
fn generate_proof<'a, I: IntoIterator<Item = Statement<'a, T>>, R: RngCore + CryptoRng>(
|
||||
program: ProgIterator<'a, T, I>,
|
||||
witness: Witness<T>,
|
||||
proving_key: Vec<u8>,
|
||||
rng: &mut R,
|
||||
) -> Proof<T, G16> {
|
||||
println!("{}", G16_WARNING);
|
||||
|
||||
let computation = Computation::with_witness(program, witness);
|
||||
let params = Parameters::read(proving_key.as_slice(), true).unwrap();
|
||||
|
||||
|
@ -37,7 +35,7 @@ impl<T: Field + BellmanFieldExtensions> Backend<T, G16> for Bellman {
|
|||
.map(|e| format!("0x{}", to_hex(e)))
|
||||
.collect();
|
||||
|
||||
let proof = computation.prove(¶ms);
|
||||
let proof = computation.prove(¶ms, rng);
|
||||
let proof_points = ProofPoints {
|
||||
a: parse_g1::<T>(&proof.a),
|
||||
b: parse_g2::<T>(&proof.b),
|
||||
|
@ -84,12 +82,11 @@ impl<T: Field + BellmanFieldExtensions> Backend<T, G16> for Bellman {
|
|||
}
|
||||
|
||||
impl<T: Field + BellmanFieldExtensions> NonUniversalBackend<T, G16> for Bellman {
|
||||
fn setup<'a, I: IntoIterator<Item = Statement<'a, T>>>(
|
||||
fn setup<'a, I: IntoIterator<Item = Statement<'a, T>>, R: RngCore + CryptoRng>(
|
||||
program: ProgIterator<'a, T, I>,
|
||||
rng: &mut R,
|
||||
) -> SetupKeypair<T, G16> {
|
||||
println!("{}", G16_WARNING);
|
||||
|
||||
let parameters = Computation::without_witness(program).setup();
|
||||
let parameters = Computation::without_witness(program).setup(rng);
|
||||
let mut pk: Vec<u8> = Vec::new();
|
||||
parameters.write(&mut pk).unwrap();
|
||||
|
||||
|
@ -110,7 +107,7 @@ impl<T: Field + BellmanFieldExtensions> MpcBackend<T, G16> for Bellman {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn contribute<R: Read, W: Write, G: Rng>(
|
||||
fn contribute<R: Read, W: Write, G: RngCore + CryptoRng>(
|
||||
params: &mut R,
|
||||
rng: &mut G,
|
||||
output: &mut W,
|
||||
|
@ -118,6 +115,9 @@ impl<T: Field + BellmanFieldExtensions> MpcBackend<T, G16> for Bellman {
|
|||
let mut params =
|
||||
MPCParameters::<T::BellmanEngine>::read(params, true).map_err(|e| e.to_string())?;
|
||||
|
||||
let seed = get_random_seed(rng);
|
||||
let rng = &mut ChaChaRng::from_seed(seed.as_ref());
|
||||
|
||||
let hash = params.contribute(rng);
|
||||
params.write(output).map_err(|e| e.to_string())?;
|
||||
|
||||
|
@ -199,6 +199,8 @@ pub mod serialization {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rand_0_8::rngs::StdRng;
|
||||
use rand_0_8::SeedableRng;
|
||||
use zokrates_field::Bn128Field;
|
||||
use zokrates_interpreter::Interpreter;
|
||||
|
||||
|
@ -214,15 +216,18 @@ mod tests {
|
|||
statements: vec![Statement::constraint(Variable::new(0), Variable::public(0))],
|
||||
};
|
||||
|
||||
let keypair = <Bellman as NonUniversalBackend<Bn128Field, G16>>::setup(program.clone());
|
||||
let rng = &mut StdRng::from_entropy();
|
||||
let keypair =
|
||||
<Bellman as NonUniversalBackend<Bn128Field, G16>>::setup(program.clone(), rng);
|
||||
let interpreter = Interpreter::default();
|
||||
|
||||
let witness = interpreter
|
||||
.execute(program.clone(), &[Bn128Field::from(42)])
|
||||
.unwrap();
|
||||
|
||||
let proof =
|
||||
<Bellman as Backend<Bn128Field, G16>>::generate_proof(program, witness, keypair.pk);
|
||||
let proof = <Bellman as Backend<Bn128Field, G16>>::generate_proof(
|
||||
program, witness, keypair.pk, rng,
|
||||
);
|
||||
let ans = <Bellman as Backend<Bn128Field, G16>>::verify(keypair.vk, proof);
|
||||
|
||||
assert!(ans);
|
||||
|
|
|
@ -16,6 +16,7 @@ use zokrates_field::BellmanFieldExtensions;
|
|||
use zokrates_field::Field;
|
||||
|
||||
use rand_0_4::ChaChaRng;
|
||||
use rand_0_8::{CryptoRng, RngCore};
|
||||
|
||||
pub use self::parse::*;
|
||||
|
||||
|
@ -148,24 +149,28 @@ impl<'a, T: BellmanFieldExtensions + Field, I: IntoIterator<Item = Statement<'a,
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_random_seed<R: RngCore + CryptoRng>(rng: &mut R) -> [u32; 8] {
|
||||
let mut seed = [0u8; 32];
|
||||
rng.fill_bytes(&mut seed);
|
||||
|
||||
use std::mem::transmute;
|
||||
// This is safe because we are just reinterpreting the bytes (u8[32] -> u32[8]),
|
||||
// byte order or the actual content does not matter here as this is used
|
||||
// as a random seed for the rng (rand 0.4)
|
||||
let seed: [u32; 8] = unsafe { transmute(seed) };
|
||||
seed
|
||||
}
|
||||
|
||||
impl<'a, T: BellmanFieldExtensions + Field, I: IntoIterator<Item = Statement<'a, T>>>
|
||||
Computation<'a, T, I>
|
||||
{
|
||||
fn get_random_seed(&self) -> Result<[u32; 8], getrandom::Error> {
|
||||
let mut seed = [0u8; 32];
|
||||
getrandom::getrandom(&mut seed)?;
|
||||
|
||||
use std::mem::transmute;
|
||||
// This is safe because we are just reinterpreting the bytes (u8[32] -> u32[8]),
|
||||
// byte order or the actual content does not matter here as this is used
|
||||
// as a random seed for the rng.
|
||||
let seed: [u32; 8] = unsafe { transmute(seed) };
|
||||
Ok(seed)
|
||||
}
|
||||
|
||||
pub fn prove(self, params: &Parameters<T::BellmanEngine>) -> Proof<T::BellmanEngine> {
|
||||
pub fn prove<R: RngCore + CryptoRng>(
|
||||
self,
|
||||
params: &Parameters<T::BellmanEngine>,
|
||||
rng: &mut R,
|
||||
) -> Proof<T::BellmanEngine> {
|
||||
use rand_0_4::SeedableRng;
|
||||
let seed = self.get_random_seed().unwrap();
|
||||
let seed = get_random_seed(rng);
|
||||
let rng = &mut ChaChaRng::from_seed(seed.as_ref());
|
||||
|
||||
// extract public inputs
|
||||
|
@ -188,9 +193,9 @@ impl<'a, T: BellmanFieldExtensions + Field, I: IntoIterator<Item = Statement<'a,
|
|||
.collect()
|
||||
}
|
||||
|
||||
pub fn setup(self) -> Parameters<T::BellmanEngine> {
|
||||
pub fn setup<R: RngCore + CryptoRng>(self, rng: &mut R) -> Parameters<T::BellmanEngine> {
|
||||
use rand_0_4::SeedableRng;
|
||||
let seed = self.get_random_seed().unwrap();
|
||||
let seed = get_random_seed(rng);
|
||||
let rng = &mut ChaChaRng::from_seed(seed.as_ref());
|
||||
// run setup phase
|
||||
generate_random_parameters(self, rng).unwrap()
|
||||
|
@ -246,6 +251,8 @@ mod tests {
|
|||
|
||||
mod prove {
|
||||
use super::*;
|
||||
use rand_0_8::rngs::StdRng;
|
||||
use rand_0_8::SeedableRng;
|
||||
use zokrates_ast::flat::Parameter;
|
||||
use zokrates_ast::ir::Prog;
|
||||
|
||||
|
@ -258,8 +265,9 @@ mod tests {
|
|||
let witness = interpreter.execute(program.clone(), &[]).unwrap();
|
||||
let computation = Computation::with_witness(program, witness);
|
||||
|
||||
let params = computation.clone().setup();
|
||||
let _proof = computation.prove(¶ms);
|
||||
let rng = &mut StdRng::from_entropy();
|
||||
let params = computation.clone().setup(rng);
|
||||
let _proof = computation.prove(¶ms, rng);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -278,8 +286,9 @@ mod tests {
|
|||
|
||||
let computation = Computation::with_witness(program, witness);
|
||||
|
||||
let params = computation.clone().setup();
|
||||
let _proof = computation.prove(¶ms);
|
||||
let rng = &mut StdRng::from_entropy();
|
||||
let params = computation.clone().setup(rng);
|
||||
let _proof = computation.prove(¶ms, rng);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -298,8 +307,9 @@ mod tests {
|
|||
|
||||
let computation = Computation::with_witness(program, witness);
|
||||
|
||||
let params = computation.clone().setup();
|
||||
let _proof = computation.prove(¶ms);
|
||||
let rng = &mut StdRng::from_entropy();
|
||||
let params = computation.clone().setup(rng);
|
||||
let _proof = computation.prove(¶ms, rng);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -315,8 +325,9 @@ mod tests {
|
|||
let witness = interpreter.execute(program.clone(), &[]).unwrap();
|
||||
let computation = Computation::with_witness(program, witness);
|
||||
|
||||
let params = computation.clone().setup();
|
||||
let _proof = computation.prove(¶ms);
|
||||
let rng = &mut StdRng::from_entropy();
|
||||
let params = computation.clone().setup(rng);
|
||||
let _proof = computation.prove(¶ms, rng);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -348,8 +359,9 @@ mod tests {
|
|||
.unwrap();
|
||||
let computation = Computation::with_witness(program, witness);
|
||||
|
||||
let params = computation.clone().setup();
|
||||
let _proof = computation.prove(¶ms);
|
||||
let rng = &mut StdRng::from_entropy();
|
||||
let params = computation.clone().setup(rng);
|
||||
let _proof = computation.prove(¶ms, rng);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -371,8 +383,9 @@ mod tests {
|
|||
|
||||
let computation = Computation::with_witness(program, witness);
|
||||
|
||||
let params = computation.clone().setup();
|
||||
let _proof = computation.prove(¶ms);
|
||||
let rng = &mut StdRng::from_entropy();
|
||||
let params = computation.clone().setup(rng);
|
||||
let _proof = computation.prove(¶ms, rng);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -396,8 +409,9 @@ mod tests {
|
|||
.unwrap();
|
||||
let computation = Computation::with_witness(program, witness);
|
||||
|
||||
let params = computation.clone().setup();
|
||||
let _proof = computation.prove(¶ms);
|
||||
let rng = &mut StdRng::from_entropy();
|
||||
let params = computation.clone().setup(rng);
|
||||
let _proof = computation.prove(¶ms, rng);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
## Assembly
|
||||
|
||||
ZoKrates allows developers to define constraints through assembly blocks. Assembly blocks are considered **unsafe**, as safety and correctness of the resulting arithmetic circuit is in the hands of the developer. Usage of assembly is recommended only in optimization efforts for the experienced developers to minimize constraint count of an arithmetic circuit.
|
||||
ZoKrates allows developers to define constraints through assembly blocks. Assembly blocks are considered **unsafe**, as safety and correctness of the resulting arithmetic circuit is in the hands of the developer. Usage of assembly is recommended only in optimization efforts for experienced developers to minimize constraint count of an arithmetic circuit.
|
||||
|
||||
>The usage of assembly blocks in ZoKrates is experimental. In particular, while assembly blocks help minimise constraint count in some cases, they currently can at the same time lead to larger compiler output and slower witness generation.
|
||||
|
||||
## Writing assembly
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ We will start this tutorial by using ZoKrates to compile a basic program.
|
|||
First, we create a new file named `program.zok` with the following content:
|
||||
|
||||
```zokrates
|
||||
{{#include ../../../zokrates_cli/examples/book/mpc_tutorial/circuit.zok}}
|
||||
{{#include ../../../zokrates_cli/examples/book/mpc_tutorial/program.zok}}
|
||||
```
|
||||
|
||||
We compile the program using the `compile` command.
|
||||
|
|
|
@ -8,118 +8,140 @@ npm install zokrates-js
|
|||
|
||||
## Importing
|
||||
|
||||
##### Bundlers
|
||||
**Note:** As this library uses a model where the wasm module itself is natively an ES module, you will need a bundler of some form.
|
||||
Currently the only known bundler known to be fully compatible with `zokrates-js` is [Webpack](https://webpack.js.org/) (`experiments.syncWebAssembly` must be enabled).
|
||||
The choice of this default was done to reflect the trends of the JS ecosystem.
|
||||
#### ES modules
|
||||
|
||||
```js
|
||||
import { initialize } from 'zokrates-js';
|
||||
import { initialize } from "zokrates-js";
|
||||
```
|
||||
|
||||
##### Node
|
||||
#### CommonJS
|
||||
|
||||
```js
|
||||
const { initialize } = require('zokrates-js')
|
||||
let { initialize } = await import("zokrates-js");
|
||||
```
|
||||
|
||||
#### CDN
|
||||
|
||||
```html
|
||||
<script src="https://unpkg.com/zokrates-js@latest/umd.min.js"></script>
|
||||
<script>
|
||||
zokrates.initialize().then((zokratesProvider) => {
|
||||
/* ... */
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
initialize().then((zokratesProvider) => {
|
||||
const source = "def main(private field a) -> field { return a * a; }";
|
||||
const source = "def main(private field a) -> field { return a * a; }";
|
||||
|
||||
// compilation
|
||||
const artifacts = zokratesProvider.compile(source);
|
||||
// compilation
|
||||
const artifacts = zokratesProvider.compile(source);
|
||||
|
||||
// computation
|
||||
const { witness, output } = zokratesProvider.computeWitness(artifacts, ["2"]);
|
||||
// computation
|
||||
const { witness, output } = zokratesProvider.computeWitness(artifacts, ["2"]);
|
||||
|
||||
// run setup
|
||||
const keypair = zokratesProvider.setup(artifacts.program);
|
||||
// run setup
|
||||
const keypair = zokratesProvider.setup(artifacts.program);
|
||||
|
||||
// generate proof
|
||||
const proof = zokratesProvider.generateProof(artifacts.program, witness, keypair.pk);
|
||||
// generate proof
|
||||
const proof = zokratesProvider.generateProof(
|
||||
artifacts.program,
|
||||
witness,
|
||||
keypair.pk
|
||||
);
|
||||
|
||||
// export solidity verifier
|
||||
const verifier = zokratesProvider.exportSolidityVerifier(keypair.vk);
|
||||
|
||||
// or verify off-chain
|
||||
const isVerified = zokratesProvider.verify(keypair.vk, proof);
|
||||
// export solidity verifier
|
||||
const verifier = zokratesProvider.exportSolidityVerifier(keypair.vk);
|
||||
|
||||
// or verify off-chain
|
||||
const isVerified = zokratesProvider.verify(keypair.vk, proof);
|
||||
});
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
##### initialize()
|
||||
|
||||
Returns an initialized `ZoKratesProvider` as a promise.
|
||||
|
||||
```js
|
||||
initialize().then((zokratesProvider) => {
|
||||
// call api functions here
|
||||
initialize().then((zokratesProvider) => {
|
||||
// call api functions here
|
||||
});
|
||||
```
|
||||
|
||||
Returns: `Promise<ZoKratesProvider>`
|
||||
|
||||
##### withOptions(options)
|
||||
|
||||
Returns a `ZoKratesProvider` configured with given options.
|
||||
|
||||
```js
|
||||
initialize().then((defaultProvider) => {
|
||||
let zokratesProvider = defaultProvider.withOptions({
|
||||
backend: "ark",
|
||||
curve: "bls12_381",
|
||||
scheme: "g16"
|
||||
});
|
||||
// ...
|
||||
initialize().then((defaultProvider) => {
|
||||
let zokratesProvider = defaultProvider.withOptions({
|
||||
backend: "ark",
|
||||
curve: "bls12_381",
|
||||
scheme: "g16",
|
||||
});
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
Options:
|
||||
* `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`)
|
||||
|
||||
- `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`
|
||||
|
||||
##### compile(source[, options])
|
||||
|
||||
Compiles source code into ZoKrates internal representation of arithmetic circuits.
|
||||
|
||||
Parameters:
|
||||
* `source` - Source code to compile
|
||||
* `options` - Compilation options
|
||||
|
||||
- `source` - Source code to compile
|
||||
- `options` - Compilation options
|
||||
|
||||
Returns: `CompilationArtifacts`
|
||||
|
||||
**Examples:**
|
||||
|
||||
Compilation:
|
||||
|
||||
```js
|
||||
const artifacts = zokratesProvider.compile("def main() { return; }");
|
||||
```
|
||||
|
||||
Compilation with custom options:
|
||||
|
||||
```js
|
||||
const source = "...";
|
||||
const options = {
|
||||
location: "main.zok", // location of the root module
|
||||
resolveCallback: (currentLocation, importLocation) => {
|
||||
console.log(currentLocation + ' is importing ' + importLocation);
|
||||
return {
|
||||
source: "def main() { return; }",
|
||||
location: importLocation
|
||||
};
|
||||
}
|
||||
location: "main.zok", // location of the root module
|
||||
resolveCallback: (currentLocation, importLocation) => {
|
||||
console.log(currentLocation + " is importing " + importLocation);
|
||||
return {
|
||||
source: "def main() { return; }",
|
||||
location: importLocation,
|
||||
};
|
||||
},
|
||||
};
|
||||
const artifacts = zokratesProvider.compile(source, options);
|
||||
```
|
||||
|
||||
**Note:** The `resolveCallback` function is used to resolve dependencies.
|
||||
This callback receives the current module location and the import location of the module which is being imported.
|
||||
The callback must synchronously return either an error, `null` or a valid `ResolverResult` object like shown in the example above.
|
||||
A simple file system resolver for a node environment can be implemented as follows:
|
||||
**Note:** The `resolveCallback` function is used to resolve dependencies.
|
||||
This callback receives the current module location and the import location of the module which is being imported.
|
||||
The callback must synchronously return either an error, `null` or a valid `ResolverResult` object like shown in the example above.
|
||||
A simple file system resolver in a node environment can be implemented as follows:
|
||||
|
||||
```js
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
const fileSystemResolver = (from, to) => {
|
||||
const location = path.resolve(path.dirname(path.resolve(from)), to);
|
||||
|
@ -129,19 +151,21 @@ const fileSystemResolver = (from, to) => {
|
|||
```
|
||||
|
||||
##### computeWitness(artifacts, args[, options])
|
||||
|
||||
Computes a valid assignment of the variables, which include the results of the computation.
|
||||
|
||||
Parameters:
|
||||
* `artifacts` - Compilation artifacts
|
||||
* `args` - Array of arguments (eg. `["1", "2", true]`)
|
||||
* `options` - Computation options
|
||||
|
||||
- `artifacts` - Compilation artifacts
|
||||
- `args` - Array of arguments (eg. `["1", "2", true]`)
|
||||
- `options` - Computation options
|
||||
|
||||
Returns: `ComputationResult`
|
||||
|
||||
**Example:**
|
||||
|
||||
```js
|
||||
const code = 'def main(private field a) -> field { return a * a; }';
|
||||
const code = "def main(private field a) -> field { return a * a; }";
|
||||
const artifacts = zokratesProvider.compile(code);
|
||||
|
||||
const { witness, output } = zokratesProvider.computeWitness(artifacts, ["2"]);
|
||||
|
@ -150,54 +174,79 @@ console.log(witness); // Resulting witness which can be used to generate a proof
|
|||
console.log(output); // Computation output: "4"
|
||||
```
|
||||
|
||||
##### setup(program)
|
||||
##### setup(program[, entropy])
|
||||
|
||||
Generates a trusted setup for the compiled program.
|
||||
|
||||
Parameters:
|
||||
* `program` - Compiled program
|
||||
|
||||
- `program` - Compiled program
|
||||
- `entropy` - User provided randomness (optional)
|
||||
|
||||
Returns: `SetupKeypair`
|
||||
|
||||
##### universalSetup(size)
|
||||
##### universalSetup(size[, entropy])
|
||||
|
||||
Performs the universal phase of a trusted setup. Only available for the `marlin` scheme.
|
||||
|
||||
Parameters:
|
||||
* `size` - Size of the trusted setup passed as an exponent. For example, `8` for `2**8`.
|
||||
|
||||
- `size` - Size of the trusted setup passed as an exponent. For example, `8` for `2**8`.
|
||||
- `entropy` - User provided randomness (optional)
|
||||
|
||||
Returns: `Uint8Array`
|
||||
|
||||
##### setupWithSrs(srs, program)
|
||||
|
||||
Generates a trusted setup with universal public parameters for the compiled program. Only available for `marlin` scheme.
|
||||
|
||||
Parameters:
|
||||
* `srs` - Universal public parameters from the universal setup phase
|
||||
* `program` - Compiled program
|
||||
|
||||
- `srs` - Universal public parameters from the universal setup phase
|
||||
- `program` - Compiled program
|
||||
|
||||
Returns: `SetupKeypair`
|
||||
|
||||
##### generateProof(program, witness, provingKey)
|
||||
##### generateProof(program, witness, provingKey[, entropy])
|
||||
|
||||
Generates a proof for a computation of the compiled program.
|
||||
|
||||
Parameters:
|
||||
* `program` - Compiled program
|
||||
* `witness` - Witness (valid assignment of the variables) from the computation result
|
||||
* `provingKey` - Proving key from the setup keypair
|
||||
|
||||
- `program` - Compiled program
|
||||
- `witness` - Witness (valid assignment of the variables) from the computation result
|
||||
- `provingKey` - Proving key from the setup keypair
|
||||
- `entropy` - User provided randomness (optional)
|
||||
|
||||
Returns: `Proof`
|
||||
|
||||
##### verify(verificationKey, proof)
|
||||
|
||||
Verifies the generated proof.
|
||||
|
||||
Parameters:
|
||||
* `verificationKey` - Verification key from the setup keypair
|
||||
* `proof` - Generated proof
|
||||
|
||||
- `verificationKey` - Verification key from the setup keypair
|
||||
- `proof` - Generated proof
|
||||
|
||||
Returns: `boolean`
|
||||
|
||||
##### exportSolidityVerifier(verificationKey)
|
||||
|
||||
Generates a Solidity contract which contains the generated verification key and a public function to verify proofs of computation of the compiled program.
|
||||
|
||||
Parameters:
|
||||
* `verificationKey` - Verification key from the setup keypair
|
||||
|
||||
- `verificationKey` - Verification key from the setup keypair
|
||||
|
||||
Returns: `string`
|
||||
|
||||
##### utils.formatProof(proof)
|
||||
|
||||
Formats the proof into an array of field elements that are compatible as input to the generated solidity contract
|
||||
|
||||
Parameters:
|
||||
|
||||
- `proof` - Generated proof
|
||||
|
||||
Returns: `array`
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_circom"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_cli"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
authors = ["Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>", "Dennis Kuhnert <mail@kyroy.com>", "Thibaut Schaeffer <thibaut@schaeff.fr>"]
|
||||
repository = "https://github.com/Zokrates/ZoKrates.git"
|
||||
edition = "2018"
|
||||
|
@ -17,12 +17,13 @@ cfg-if = "0.1"
|
|||
clap = "2.26.2"
|
||||
serde_cbor = "0.11.2"
|
||||
regex = "0.2"
|
||||
zokrates_field = { version = "0.5", path = "../zokrates_field", default-features = false }
|
||||
zokrates_field = { version = "0.5", path = "../zokrates_field", features = ["multicore"] }
|
||||
zokrates_abi = { version = "0.1", path = "../zokrates_abi" }
|
||||
zokrates_core = { version = "0.7", path = "../zokrates_core", default-features = false }
|
||||
zokrates_ast = { version = "0.1", path = "../zokrates_ast", default-features = false }
|
||||
zokrates_interpreter = { version = "0.1", path = "../zokrates_interpreter", default-features = false }
|
||||
zokrates_circom = { version = "0.1", path = "../zokrates_circom", default-features = false }
|
||||
zokrates_embed = { version = "0.1", path = "../zokrates_embed", features = ["multicore"] }
|
||||
typed-arena = "1.4.1"
|
||||
zokrates_fs_resolver = { version = "0.5", path = "../zokrates_fs_resolver"}
|
||||
zokrates_common = { version = "0.1", path = "../zokrates_common", default-features = false }
|
||||
|
@ -39,14 +40,13 @@ sha2 = "0.10.0"
|
|||
|
||||
# Backends
|
||||
zokrates_proof_systems = { version = "0.1", path = "../zokrates_proof_systems", default-features = false }
|
||||
zokrates_ark = { version = "0.1", path = "../zokrates_ark", default-features = false, optional = true }
|
||||
zokrates_bellman = { version = "0.1", path = "../zokrates_bellman", default-features = false, optional = true }
|
||||
zokrates_ark = { version = "0.1", path = "../zokrates_ark", features = ["multicore"], optional = true }
|
||||
zokrates_bellman = { version = "0.1", path = "../zokrates_bellman", features = ["multicore"], optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
glob = "0.2.11"
|
||||
assert_cli = "0.5"
|
||||
tempdir = "0.3"
|
||||
zokrates_solidity_test = { version = "0.1", path = "../zokrates_solidity_test", default-features = false }
|
||||
ethabi = "17.0.0"
|
||||
primitive-types = { version = "0.11", features = ["rlp"] }
|
||||
fs_extra = "1.1.0"
|
||||
|
|
|
@ -7,8 +7,8 @@ function zokrates() {
|
|||
ZOKRATES_STDLIB=$stdlib $bin "$@"
|
||||
}
|
||||
|
||||
# compile the circuit
|
||||
zokrates compile -i circuit.zok -o circuit
|
||||
# compile the program
|
||||
zokrates compile -i program.zok -o circuit
|
||||
|
||||
# initialize the ceremony
|
||||
# this step requires phase1 files eg. phase1radix2m2 for circuits of 2^2 constraints
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use crate::cli_constants;
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use rand_0_8::rngs::StdRng;
|
||||
use rand_0_8::SeedableRng;
|
||||
use std::convert::TryFrom;
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, Read, Write};
|
||||
|
@ -12,6 +14,7 @@ use zokrates_bellman::Bellman;
|
|||
use zokrates_common::constants;
|
||||
use zokrates_common::helpers::*;
|
||||
use zokrates_field::Field;
|
||||
use zokrates_proof_systems::rng::get_rng_from_entropy;
|
||||
#[cfg(any(feature = "bellman", feature = "ark"))]
|
||||
use zokrates_proof_systems::*;
|
||||
|
||||
|
@ -79,6 +82,14 @@ pub fn subcommand() -> App<'static, 'static> {
|
|||
.possible_values(cli_constants::SCHEMES)
|
||||
.default_value(constants::G16),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("entropy")
|
||||
.short("e")
|
||||
.long("entropy")
|
||||
.help("User provided randomness")
|
||||
.takes_value(true)
|
||||
.required(false),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
|
||||
|
@ -167,7 +178,12 @@ fn cli_generate_proof<
|
|||
.read_to_end(&mut pk)
|
||||
.map_err(|why| format!("Could not read {}: {}", pk_path.display(), why))?;
|
||||
|
||||
let proof = B::generate_proof(program, witness, pk);
|
||||
let mut rng = sub_matches
|
||||
.value_of("entropy")
|
||||
.map(get_rng_from_entropy)
|
||||
.unwrap_or_else(StdRng::from_entropy);
|
||||
|
||||
let proof = B::generate_proof(program, witness, pk, &mut rng);
|
||||
let mut proof_file = File::create(proof_path).unwrap();
|
||||
|
||||
let proof =
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::cli_constants::MPC_DEFAULT_PATH;
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use rand_0_8::{rngs::StdRng, SeedableRng};
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, BufWriter};
|
||||
use std::path::Path;
|
||||
|
@ -87,9 +88,7 @@ fn cli_mpc_beacon<T: Field + BellmanFieldExtensions, S: MpcScheme<T>, B: MpcBack
|
|||
|
||||
// Create an RNG based on the outcome of the random beacon
|
||||
let mut rng = {
|
||||
use byteorder::{BigEndian, ReadBytesExt};
|
||||
use rand_0_4::chacha::ChaChaRng;
|
||||
use rand_0_4::SeedableRng;
|
||||
use byteorder::ReadBytesExt;
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
// The hash used for the beacon
|
||||
|
@ -126,12 +125,12 @@ fn cli_mpc_beacon<T: Field + BellmanFieldExtensions, S: MpcScheme<T>, B: MpcBack
|
|||
|
||||
let mut digest = &cur_hash[..];
|
||||
|
||||
let mut seed = [0u32; 8];
|
||||
let mut seed = [0u8; 32];
|
||||
for e in &mut seed {
|
||||
*e = digest.read_u32::<BigEndian>().unwrap();
|
||||
*e = digest.read_u8().unwrap();
|
||||
}
|
||||
|
||||
ChaChaRng::from_seed(&seed)
|
||||
StdRng::from_seed(seed)
|
||||
};
|
||||
|
||||
let output_path = Path::new(sub_matches.value_of("output").unwrap());
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
use crate::cli_constants::MPC_DEFAULT_PATH;
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use rand_0_8::{rngs::StdRng, SeedableRng};
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, BufWriter};
|
||||
use std::path::Path;
|
||||
use zokrates_bellman::Bellman;
|
||||
use zokrates_common::constants::{BLS12_381, BN128};
|
||||
use zokrates_field::{BellmanFieldExtensions, Bls12_381Field, Bn128Field, Field};
|
||||
use zokrates_proof_systems::rng::get_rng_from_entropy;
|
||||
use zokrates_proof_systems::{MpcBackend, MpcScheme, G16};
|
||||
|
||||
pub fn subcommand() -> App<'static, 'static> {
|
||||
|
@ -71,40 +73,6 @@ pub fn cli_mpc_contribute<
|
|||
File::open(&path).map_err(|why| format!("Could not open `{}`: {}", path.display(), why))?;
|
||||
|
||||
let mut reader = BufReader::new(file);
|
||||
let entropy = sub_matches.value_of("entropy").unwrap();
|
||||
|
||||
// Create an RNG based on a mixture of system randomness and user provided randomness
|
||||
let mut rng = {
|
||||
use blake2::{Blake2b, Digest};
|
||||
use byteorder::{BigEndian, ReadBytesExt};
|
||||
use rand_0_4::chacha::ChaChaRng;
|
||||
use rand_0_4::{OsRng, Rng, SeedableRng};
|
||||
|
||||
let h = {
|
||||
let mut system_rng = OsRng::new().unwrap();
|
||||
let mut h = Blake2b::default();
|
||||
|
||||
// Gather 1024 bytes of entropy from the system
|
||||
for _ in 0..1024 {
|
||||
let r: u8 = system_rng.gen();
|
||||
h.input(&[r]);
|
||||
}
|
||||
|
||||
// Hash it all up to make a seed
|
||||
h.input(&entropy.as_bytes());
|
||||
h.result()
|
||||
};
|
||||
|
||||
let mut digest = &h[..];
|
||||
|
||||
// Interpret the first 32 bytes of the digest as 8 32-bit words
|
||||
let mut seed = [0u32; 8];
|
||||
for e in &mut seed {
|
||||
*e = digest.read_u32::<BigEndian>().unwrap();
|
||||
}
|
||||
|
||||
ChaChaRng::from_seed(&seed)
|
||||
};
|
||||
|
||||
let output_path = Path::new(sub_matches.value_of("output").unwrap());
|
||||
let output_file = File::create(&output_path)
|
||||
|
@ -114,6 +82,11 @@ pub fn cli_mpc_contribute<
|
|||
|
||||
println!("Contributing to `{}`...", path.display());
|
||||
|
||||
let mut rng = sub_matches
|
||||
.value_of("entropy")
|
||||
.map(get_rng_from_entropy)
|
||||
.unwrap_or_else(StdRng::from_entropy);
|
||||
|
||||
let hash = B::contribute(&mut reader, &mut rng, &mut writer)
|
||||
.map_err(|e| format!("Failed to contribute: {}", e))?;
|
||||
println!("The BLAKE2b hash of your contribution is:\n");
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use clap::{App, ArgMatches, SubCommand};
|
||||
use clap::{App, AppSettings, ArgMatches, SubCommand};
|
||||
|
||||
pub mod beacon;
|
||||
pub mod contribute;
|
||||
|
@ -9,6 +9,7 @@ pub mod verify;
|
|||
pub fn subcommand() -> App<'static, 'static> {
|
||||
SubCommand::with_name("mpc")
|
||||
.about("Multi-party computation (MPC) protocol")
|
||||
.setting(AppSettings::SubcommandRequiredElseHelp)
|
||||
.subcommands(vec![
|
||||
init::subcommand().display_order(1),
|
||||
contribute::subcommand().display_order(2),
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use crate::cli_constants;
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use rand_0_8::rngs::StdRng;
|
||||
use rand_0_8::SeedableRng;
|
||||
use std::convert::TryFrom;
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, Write};
|
||||
|
@ -12,6 +14,7 @@ use zokrates_bellman::Bellman;
|
|||
use zokrates_common::constants;
|
||||
use zokrates_common::helpers::*;
|
||||
use zokrates_field::Field;
|
||||
use zokrates_proof_systems::rng::get_rng_from_entropy;
|
||||
#[cfg(any(feature = "bellman", feature = "ark"))]
|
||||
use zokrates_proof_systems::*;
|
||||
|
||||
|
@ -78,6 +81,14 @@ pub fn subcommand() -> App<'static, 'static> {
|
|||
.required(false)
|
||||
.default_value(cli_constants::UNIVERSAL_SETUP_DEFAULT_PATH),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("entropy")
|
||||
.short("e")
|
||||
.long("entropy")
|
||||
.help("User provided randomness")
|
||||
.takes_value(true)
|
||||
.required(false),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
|
||||
|
@ -182,8 +193,13 @@ fn cli_setup_non_universal<
|
|||
let pk_path = Path::new(sub_matches.value_of("proving-key-path").unwrap());
|
||||
let vk_path = Path::new(sub_matches.value_of("verification-key-path").unwrap());
|
||||
|
||||
let mut rng = sub_matches
|
||||
.value_of("entropy")
|
||||
.map(get_rng_from_entropy)
|
||||
.unwrap_or_else(StdRng::from_entropy);
|
||||
|
||||
// run setup phase
|
||||
let keypair = B::setup(program);
|
||||
let keypair = B::setup(program, &mut rng);
|
||||
|
||||
// write verification key
|
||||
let mut vk_file = File::create(vk_path)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use crate::cli_constants;
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use rand_0_8::rngs::StdRng;
|
||||
use rand_0_8::SeedableRng;
|
||||
use std::convert::TryFrom;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
|
@ -9,6 +11,7 @@ use zokrates_ark::Ark;
|
|||
use zokrates_common::constants;
|
||||
use zokrates_common::helpers::*;
|
||||
use zokrates_field::{Bls12_377Field, Bls12_381Field, Bn128Field, Bw6_761Field, Field};
|
||||
use zokrates_proof_systems::rng::get_rng_from_entropy;
|
||||
#[cfg(any(feature = "bellman", feature = "ark"))]
|
||||
use zokrates_proof_systems::*;
|
||||
|
||||
|
@ -54,6 +57,14 @@ pub fn subcommand() -> App<'static, 'static> {
|
|||
.required(false)
|
||||
.default_value(cli_constants::UNIVERSAL_SETUP_DEFAULT_SIZE),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("entropy")
|
||||
.short("e")
|
||||
.long("entropy")
|
||||
.help("User provided randomness")
|
||||
.takes_value(true)
|
||||
.required(false),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
|
||||
|
@ -98,8 +109,13 @@ fn cli_universal_setup<T: Field, S: UniversalScheme<T>, B: UniversalBackend<T, S
|
|||
.parse::<u32>()
|
||||
.map_err(|_| format!("Universal setup size {} is invalid", size))?;
|
||||
|
||||
let mut rng = sub_matches
|
||||
.value_of("entropy")
|
||||
.map(get_rng_from_entropy)
|
||||
.unwrap_or_else(StdRng::from_entropy);
|
||||
|
||||
// run universal setup phase
|
||||
let setup = B::universal_setup(size);
|
||||
let setup = B::universal_setup(size, &mut rng);
|
||||
|
||||
// write proving key
|
||||
let mut u_file = File::create(u_path)
|
||||
|
|
|
@ -4,10 +4,10 @@ extern crate primitive_types;
|
|||
extern crate rand_0_4;
|
||||
extern crate rand_0_8;
|
||||
extern crate serde_json;
|
||||
extern crate zokrates_solidity_test;
|
||||
|
||||
#[cfg(test)]
|
||||
mod integration {
|
||||
use ethabi::Token;
|
||||
use fs_extra::copy_items;
|
||||
use fs_extra::dir::CopyOptions;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
@ -15,16 +15,16 @@ mod integration {
|
|||
use serde_json::from_reader;
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, Read};
|
||||
use std::io::{BufReader, Read, Write};
|
||||
use std::panic;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
use tempdir::TempDir;
|
||||
use zokrates_abi::{parse_strict, Encode};
|
||||
use zokrates_ast::typed::abi::Abi;
|
||||
use zokrates_field::Bn128Field;
|
||||
use zokrates_proof_systems::{
|
||||
to_token::ToToken, Marlin, Proof, SolidityCompatibleScheme, G16, GM17,
|
||||
SOLIDITY_G2_ADDITION_LIB,
|
||||
};
|
||||
|
||||
macro_rules! map(
|
||||
|
@ -41,6 +41,7 @@ mod integration {
|
|||
#[test]
|
||||
#[ignore]
|
||||
fn test_compile_and_witness_dir() {
|
||||
let forge = dirs::home_dir().unwrap().join(".foundry/bin/forge");
|
||||
let global_dir = TempDir::new("global").unwrap();
|
||||
let global_base = global_dir.path();
|
||||
let universal_setup_path = global_base.join("universal_setup.dat");
|
||||
|
@ -59,6 +60,38 @@ mod integration {
|
|||
.succeeds()
|
||||
.unwrap();
|
||||
|
||||
let solidity_test_path = global_base.join("zokrates_verifier");
|
||||
std::fs::create_dir(&solidity_test_path).unwrap();
|
||||
|
||||
Command::new(&forge)
|
||||
.output()
|
||||
.expect("Could not run `forge`. Make sure foundry is installed to run this test");
|
||||
|
||||
let output = Command::new(&forge)
|
||||
.current_dir(&solidity_test_path)
|
||||
.arg("init")
|
||||
.arg("--no-git")
|
||||
.arg("--no-commit")
|
||||
.arg(".")
|
||||
.output()
|
||||
.unwrap();
|
||||
|
||||
std::io::stdout().write_all(&output.stdout).unwrap();
|
||||
std::io::stderr().write_all(&output.stderr).unwrap();
|
||||
|
||||
assert!(output.status.success());
|
||||
|
||||
Command::new("rm")
|
||||
.current_dir(&solidity_test_path)
|
||||
.arg("./src/*.sol")
|
||||
.output()
|
||||
.unwrap();
|
||||
Command::new("rm")
|
||||
.current_dir(&solidity_test_path)
|
||||
.arg("./test/*.t.sol")
|
||||
.output()
|
||||
.unwrap();
|
||||
|
||||
let dir = Path::new("./tests/code");
|
||||
assert!(dir.is_dir());
|
||||
for entry in fs::read_dir(dir).unwrap() {
|
||||
|
@ -80,6 +113,17 @@ mod integration {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
let output = Command::new(&forge)
|
||||
.current_dir(&solidity_test_path)
|
||||
.arg("test")
|
||||
.output()
|
||||
.expect("failed to forge test");
|
||||
|
||||
std::io::stdout().write_all(&output.stdout).unwrap();
|
||||
std::io::stderr().write_all(&output.stderr).unwrap();
|
||||
|
||||
assert!(output.status.success());
|
||||
}
|
||||
|
||||
fn test_compile_and_witness(
|
||||
|
@ -106,6 +150,7 @@ mod integration {
|
|||
.join(program_name)
|
||||
.join("proving")
|
||||
.with_extension("key");
|
||||
let solidity_test_path = global_path.join("zokrates_verifier");
|
||||
let verification_contract_path = tmp_base
|
||||
.join(program_name)
|
||||
.join("verifier")
|
||||
|
@ -241,7 +286,6 @@ mod integration {
|
|||
|
||||
for (backend, schemes) in backends {
|
||||
for scheme in &schemes {
|
||||
println!("test with {}, {}", backend, scheme);
|
||||
// SETUP
|
||||
let setup = assert_cli::Assert::main_binary()
|
||||
.with_args(&[
|
||||
|
@ -324,7 +368,14 @@ mod integration {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
test_solidity_verifier(contract_str, proof);
|
||||
test_solidity_verifier(
|
||||
program_name,
|
||||
backend,
|
||||
scheme,
|
||||
&solidity_test_path,
|
||||
&contract_str,
|
||||
proof,
|
||||
);
|
||||
}
|
||||
"g16" => {
|
||||
// Get the proof
|
||||
|
@ -333,7 +384,14 @@ mod integration {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
test_solidity_verifier(contract_str, proof);
|
||||
test_solidity_verifier(
|
||||
program_name,
|
||||
backend,
|
||||
scheme,
|
||||
&solidity_test_path,
|
||||
&contract_str,
|
||||
proof,
|
||||
);
|
||||
}
|
||||
"gm17" => {
|
||||
// Get the proof
|
||||
|
@ -342,7 +400,14 @@ mod integration {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
test_solidity_verifier(contract_str, proof);
|
||||
test_solidity_verifier(
|
||||
program_name,
|
||||
backend,
|
||||
scheme,
|
||||
&solidity_test_path,
|
||||
&contract_str,
|
||||
proof,
|
||||
);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
@ -352,48 +417,13 @@ mod integration {
|
|||
}
|
||||
|
||||
fn test_solidity_verifier<S: SolidityCompatibleScheme<Bn128Field> + ToToken<Bn128Field>>(
|
||||
src: String,
|
||||
program_name: &str,
|
||||
backend: &str,
|
||||
scheme: &str,
|
||||
solidity_test_path: &Path,
|
||||
contract_str: &str,
|
||||
proof: Proof<Bn128Field, S>,
|
||||
) {
|
||||
use ethabi::Token;
|
||||
use rand_0_8::{rngs::StdRng, SeedableRng};
|
||||
use zokrates_solidity_test::{address::*, contract::*, evm::*, to_be_bytes};
|
||||
|
||||
// Setup EVM
|
||||
let mut rng = StdRng::from_seed([0; 32]);
|
||||
let mut evm = Evm::default();
|
||||
let deployer = Address::random(&mut rng);
|
||||
evm.create_account(&deployer, 0);
|
||||
|
||||
// Compile lib
|
||||
let g2_lib =
|
||||
Contract::compile_from_src_string(SOLIDITY_G2_ADDITION_LIB, "BN256G2", true, &[])
|
||||
.unwrap();
|
||||
|
||||
// Deploy lib
|
||||
let create_result = evm
|
||||
.deploy(g2_lib.encode_create_contract_bytes(&[]).unwrap(), &deployer)
|
||||
.unwrap();
|
||||
let lib_addr = create_result.addr;
|
||||
|
||||
// Compile contract
|
||||
let contract = Contract::compile_from_src_string(
|
||||
&src,
|
||||
"Verifier",
|
||||
true,
|
||||
&[("BN256G2", lib_addr.as_token())],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Deploy contract
|
||||
let create_result = evm
|
||||
.deploy(
|
||||
contract.encode_create_contract_bytes(&[]).unwrap(),
|
||||
&deployer,
|
||||
)
|
||||
.unwrap();
|
||||
let contract_addr = create_result.addr;
|
||||
|
||||
// convert to the solidity proof format
|
||||
let solidity_proof = S::Proof::from(proof.proof);
|
||||
|
||||
|
@ -412,40 +442,95 @@ mod integration {
|
|||
.collect::<Vec<_>>(),
|
||||
);
|
||||
|
||||
let inputs = [proof_token, input_token.clone()];
|
||||
|
||||
// Call verify function on contract
|
||||
let result = evm
|
||||
.call(
|
||||
contract
|
||||
.encode_call_contract_bytes("verifyTx", &inputs)
|
||||
.unwrap(),
|
||||
&contract_addr,
|
||||
&deployer,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(&result.out, &to_be_bytes(&U256::from(1)));
|
||||
let inputs = ethabi::encode(&[proof_token, input_token.clone()]);
|
||||
|
||||
// modify the proof
|
||||
let modified_solidity_proof = S::modify(solidity_proof);
|
||||
|
||||
let modified_proof_token = S::to_token(modified_solidity_proof);
|
||||
|
||||
let inputs = [modified_proof_token, input_token];
|
||||
let modified_inputs = ethabi::encode(&[modified_proof_token, input_token]);
|
||||
|
||||
// Call verify function on contract
|
||||
let result = evm
|
||||
.call(
|
||||
contract
|
||||
.encode_call_contract_bytes("verifyTx", &inputs)
|
||||
.unwrap(),
|
||||
&contract_addr,
|
||||
&deployer,
|
||||
)
|
||||
.unwrap();
|
||||
let verifier_name = format!("Verifier_{}_{}_{}", program_name, scheme, backend);
|
||||
|
||||
assert_eq!(result.op_out, Return::InvalidOpcode);
|
||||
let verifier_path = solidity_test_path
|
||||
.join("src")
|
||||
.join(&verifier_name)
|
||||
.with_extension("sol");
|
||||
let mut file = File::create(verifier_path).unwrap();
|
||||
write!(file, "{}", contract_str).unwrap();
|
||||
|
||||
let test_path = solidity_test_path
|
||||
.join("test")
|
||||
.join(format!(
|
||||
"Verifier_{}_{}_{}_Test",
|
||||
program_name, scheme, backend
|
||||
))
|
||||
.with_extension("t.sol");
|
||||
let mut file = File::create(test_path).unwrap();
|
||||
let test_content = format!(
|
||||
r#"
|
||||
|
||||
pragma solidity ^0.8.17;
|
||||
|
||||
import "forge-std/Test.sol";
|
||||
import "../src/{}.sol";
|
||||
|
||||
contract VerifierTest is Test {{
|
||||
Verifier public verifier;
|
||||
|
||||
constructor() {{
|
||||
verifier = new Verifier();
|
||||
}}
|
||||
|
||||
function testValidProof() public {{
|
||||
bytes4 selector = verifier.verifyTx.selector;
|
||||
uint8[{}] memory b = [{}];
|
||||
bytes memory data = new bytes(b.length + 4);
|
||||
for(uint i; i < 4; i++) {{
|
||||
data[i] = selector[i];
|
||||
}}
|
||||
for(uint i; i < b.length; i++) {{
|
||||
data[i + 4] = bytes1(b[i]);
|
||||
}}
|
||||
(bool success, bytes memory returnData) = address(verifier).call(data);
|
||||
assertEq(success, true);
|
||||
bool res = abi.decode(returnData, (bool));
|
||||
assertEq(res, true);
|
||||
}}
|
||||
|
||||
function testInvalidProof() public {{
|
||||
bytes4 selector = verifier.verifyTx.selector;
|
||||
uint8[{}] memory b = [{}];
|
||||
bytes memory data = new bytes(b.length + 4);
|
||||
for(uint i; i < 4; i++) {{
|
||||
data[i] = selector[i];
|
||||
}}
|
||||
for(uint i; i < b.length; i++) {{
|
||||
data[i + 4] = bytes1(b[i]);
|
||||
}}
|
||||
(bool success, ) = address(verifier).call(data);
|
||||
assertEq(success, false);
|
||||
}}
|
||||
}}
|
||||
|
||||
"#,
|
||||
verifier_name,
|
||||
inputs.len(),
|
||||
inputs
|
||||
.iter()
|
||||
.map(|v| format!("{:#04X?}", v))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
modified_inputs.len(),
|
||||
modified_inputs
|
||||
.iter()
|
||||
.map(|v| format!("{:#04X?}", v))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
);
|
||||
|
||||
write!(file, "{}", test_content).unwrap();
|
||||
}
|
||||
|
||||
fn test_compile_and_smtlib2(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_codegen"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_common"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
authors = ["dark64 <darem966@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_core"
|
||||
version = "0.7.2"
|
||||
version = "0.7.3"
|
||||
edition = "2021"
|
||||
authors = ["Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>", "Dennis Kuhnert <mail@kyroy.com>"]
|
||||
repository = "https://github.com/Zokrates/ZoKrates"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_core_test"
|
||||
version = "0.2.9"
|
||||
version = "0.2.10"
|
||||
authors = ["schaeff <thibaut@schaeff.fr>"]
|
||||
edition = "2018"
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"curves": ["Bn128"],
|
||||
"max_constraint_count": 0,
|
||||
"tests": []
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
def main() {
|
||||
field[2][2] mut a = [[1; 2], [1; 2]];
|
||||
a[0][0] = 0;
|
||||
field[2][2] mut b = [...[[1; 2]; 2]];
|
||||
b[0][0] = 0;
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_embed"
|
||||
version = "0.1.8"
|
||||
version = "0.1.9"
|
||||
authors = ["schaeff <thibaut@schaeff.fr>"]
|
||||
edition = "2018"
|
||||
|
||||
|
@ -8,8 +8,17 @@ edition = "2018"
|
|||
default = ["ark", "bellman"]
|
||||
ark = ["ark-bls12-377", "ark-bw6-761", "ark-gm17", "ark-relations", "ark-crypto-primitives", "ark-r1cs-std", "ark-std", "ark-ec", "ark-ff", "sapling-crypto_ce"]
|
||||
bellman = ["bellman_ce"]
|
||||
wasm = ["bellman_ce/wasm", "sapling-crypto_ce/wasm"]
|
||||
multicore = ["bellman_ce/multicore", "sapling-crypto_ce/multicore"]
|
||||
wasm = ["bellman_ce/nolog", "bellman_ce/wasm", "sapling-crypto_ce/wasm"]
|
||||
multicore = [
|
||||
"bellman_ce/multicore",
|
||||
"sapling-crypto_ce/multicore",
|
||||
"ark-gm17/parallel",
|
||||
"ark-crypto-primitives/parallel",
|
||||
"ark-r1cs-std/parallel",
|
||||
"ark-std/parallel",
|
||||
"ark-ec/parallel",
|
||||
"ark-ff/parallel"
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
zokrates_field = { version = "0.5.0", path = "../zokrates_field", default-features = false }
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
[package]
|
||||
name = "zokrates_field"
|
||||
version = "0.5.2"
|
||||
version = "0.5.3"
|
||||
authors = ["Thibaut Schaeffer <thibaut@schaeff.fr>", "Guillaume Ballet <gballet@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[features]
|
||||
default = ["bellman"]
|
||||
bellman = ["bellman_ce"]
|
||||
multicore = ["ark-ff/parallel", "ark-ec/parallel"]
|
||||
|
||||
[dependencies]
|
||||
serde = "1.0"
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
[package]
|
||||
name = "zokrates_interpreter"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
default = ["bellman", "ark"]
|
||||
bellman = ["zokrates_field/bellman", "pairing_ce", "zokrates_embed/bellman", "zokrates_ast/bellman"]
|
||||
ark = ["ark-bls12-377", "zokrates_embed/ark", "zokrates_ast/ark"]
|
||||
bellman = ["zokrates_field/bellman", "pairing_ce", "zokrates_embed/bellman", "zokrates_ast/bellman", "zokrates_analysis/bellman"]
|
||||
ark = ["ark-bls12-377", "zokrates_embed/ark", "zokrates_ast/ark", "zokrates_analysis/ark"]
|
||||
|
||||
[dependencies]
|
||||
zokrates_field = { version = "0.5", path = "../zokrates_field", default-features = false }
|
||||
|
@ -14,14 +14,9 @@ zokrates_ast = { version = "0.1", path = "../zokrates_ast", default-features = f
|
|||
zokrates_embed = { version = "0.1.0", path = "../zokrates_embed", default-features = false }
|
||||
zokrates_abi = { version = "0.1", path = "../zokrates_abi", default-features = false }
|
||||
zokrates_analysis = { version = "0.1", path = "../zokrates_analysis", default-features = false }
|
||||
|
||||
num = { version = "0.1.36", default-features = false }
|
||||
num-bigint = { version = "0.2", default-features = false }
|
||||
|
||||
ark-bls12-377 = { version = "^0.3.0", features = ["curve"], default-features = false, optional = true }
|
||||
|
||||
pairing_ce = { version = "^0.21", optional = true }
|
||||
|
||||
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
||||
|
|
6
zokrates_js/.gitignore
vendored
6
zokrates_js/.gitignore
vendored
|
@ -3,6 +3,6 @@ dist
|
|||
target
|
||||
pkg
|
||||
wasm-pack.log
|
||||
stdlib
|
||||
stdlib.js
|
||||
metadata.js
|
||||
metadata.js
|
||||
wasm.js
|
||||
umd.min.js
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_js"
|
||||
version = "1.1.4"
|
||||
version = "1.1.5"
|
||||
authors = ["Darko Macesic"]
|
||||
edition = "2018"
|
||||
|
||||
|
@ -14,19 +14,26 @@ serde_json = { version = "1.0", features = ["preserve_order"] }
|
|||
wasm-bindgen = { version = "0.2.46", features = ["serde-serialize"] }
|
||||
typed-arena = "1.4.1"
|
||||
lazy_static = "1.4.0"
|
||||
zokrates_field = { path = "../zokrates_field" }
|
||||
rand_0_8 = { version = "0.8", package = "rand" }
|
||||
getrandom = { version = "0.2.8", features = ["js"] }
|
||||
zokrates_core = { path = "../zokrates_core", default-features = false, features = ["ark", "bellman"] }
|
||||
zokrates_ark = { path = "../zokrates_ark", default-features = false}
|
||||
zokrates_bellman = { path = "../zokrates_bellman", default-features = false}
|
||||
zokrates_ark = { path = "../zokrates_ark", default-features = false }
|
||||
zokrates_embed = { path = "../zokrates_embed", default-features = false }
|
||||
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", "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", "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
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
zokrates_embed = { path = "../zokrates_embed", features = ["wasm"] }
|
||||
zokrates_bellman = { path = "../zokrates_bellman", features = ["wasm"] }
|
||||
|
||||
[build-dependencies]
|
||||
json = "0.12.4"
|
||||
walkdir = "2.3.2"
|
||||
|
|
|
@ -40,9 +40,5 @@ fn export_metadata() {
|
|||
.insert("version", config["package"]["version"].as_str().unwrap())
|
||||
.unwrap();
|
||||
|
||||
fs::write(
|
||||
"metadata.js",
|
||||
format!("module.exports = {}", metadata.dump()),
|
||||
)
|
||||
.unwrap();
|
||||
fs::write("metadata.js", format!("export default {}", metadata.dump())).unwrap();
|
||||
}
|
||||
|
|
5
zokrates_js/index-node.js
Normal file
5
zokrates_js/index-node.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
// https://docs.rs/getrandom/0.2.8/getrandom/index.html#nodejs-es-module-support
|
||||
import { webcrypto } from "node:crypto";
|
||||
globalThis.crypto = webcrypto;
|
||||
|
||||
export * from "./index.js";
|
7
zokrates_js/index.d.ts
vendored
7
zokrates_js/index.d.ts
vendored
|
@ -85,13 +85,14 @@ declare module "zokrates-js" {
|
|||
args: any[],
|
||||
options?: ComputeOptions
|
||||
): ComputationResult;
|
||||
setup(program: Uint8Array): SetupKeypair;
|
||||
universalSetup(size: number): Uint8Array;
|
||||
setup(program: Uint8Array, entropy?: string): SetupKeypair;
|
||||
universalSetup(size: number, entropy?: string): Uint8Array;
|
||||
setupWithSrs(srs: Uint8Array, program: Uint8Array): SetupKeypair;
|
||||
generateProof(
|
||||
program: Uint8Array,
|
||||
witness: string,
|
||||
provingKey: Uint8Array
|
||||
provingKey: Uint8Array,
|
||||
entropy?: string
|
||||
): Proof;
|
||||
verify(verificationKey: VerificationKey, proof: Proof): boolean;
|
||||
exportSolidityVerifier(verificationKey: VerificationKey): string;
|
||||
|
|
|
@ -1,9 +1,139 @@
|
|||
import lib from "./lib.js";
|
||||
import { inflate } from "pako";
|
||||
import metadata from "./metadata.js";
|
||||
import * as wasmExports from "./wasm.js";
|
||||
|
||||
const initialize = async () => {
|
||||
const pkg = await import("./pkg/index.js");
|
||||
return lib(pkg);
|
||||
await wasmExports.init(inflate);
|
||||
|
||||
const defaultProvider = {
|
||||
compile: (source, compileOptions = {}) => {
|
||||
var {
|
||||
curve = "bn128",
|
||||
location = "main.zok",
|
||||
resolveCallback = () => null,
|
||||
config = {},
|
||||
snarkjs = false,
|
||||
} = compileOptions;
|
||||
|
||||
config = { snarkjs, ...config };
|
||||
|
||||
const ptr = wasmExports.compile(
|
||||
source,
|
||||
location,
|
||||
resolveCallback,
|
||||
config,
|
||||
curve
|
||||
);
|
||||
const result = Object.assign(
|
||||
{
|
||||
program: ptr.program(),
|
||||
abi: ptr.abi(),
|
||||
constraintCount: ptr.constraint_count(),
|
||||
},
|
||||
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, logCallback = console.log } = computeOptions;
|
||||
const ptr = wasmExports.compute_witness(
|
||||
program,
|
||||
abi,
|
||||
JSON.stringify(args),
|
||||
{
|
||||
snarkjs: snarkjs,
|
||||
},
|
||||
logCallback
|
||||
);
|
||||
|
||||
const result = Object.assign(
|
||||
{
|
||||
witness: ptr.witness(),
|
||||
output: ptr.output(),
|
||||
},
|
||||
snarkjs
|
||||
? {
|
||||
snarkjs: {
|
||||
witness: ptr.snarkjs_witness(),
|
||||
},
|
||||
}
|
||||
: {}
|
||||
);
|
||||
|
||||
ptr.free();
|
||||
return result;
|
||||
},
|
||||
setup: (program, entropy, options) => {
|
||||
return wasmExports.setup(program, entropy, options);
|
||||
},
|
||||
universalSetup: (curve, size, entropy) => {
|
||||
return wasmExports.universal_setup(curve, size, entropy);
|
||||
},
|
||||
setupWithSrs: (srs, program, options) => {
|
||||
return wasmExports.setup_with_srs(srs, program, options);
|
||||
},
|
||||
generateProof: (program, witness, provingKey, entropy, options) => {
|
||||
return wasmExports.generate_proof(
|
||||
program,
|
||||
witness,
|
||||
provingKey,
|
||||
entropy,
|
||||
options
|
||||
);
|
||||
},
|
||||
verify: (vk, proof, options) => {
|
||||
return wasmExports.verify(vk, proof, options);
|
||||
},
|
||||
exportSolidityVerifier: (vk) => {
|
||||
return wasmExports.export_solidity_verifier(vk);
|
||||
},
|
||||
utils: {
|
||||
formatProof: (proof) => {
|
||||
return wasmExports.format_proof(proof);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const withOptions = (options) => {
|
||||
return {
|
||||
withOptions,
|
||||
compile: (source, compileOptions = {}) =>
|
||||
defaultProvider.compile(source, {
|
||||
...compileOptions,
|
||||
curve: options.curve,
|
||||
}),
|
||||
computeWitness: (artifacts, args, computeOptions = {}) =>
|
||||
defaultProvider.computeWitness(artifacts, args, computeOptions),
|
||||
setup: (program, entropy) =>
|
||||
defaultProvider.setup(program, entropy, options),
|
||||
universalSetup: (size, entropy) =>
|
||||
defaultProvider.universalSetup(options.curve, size, entropy),
|
||||
setupWithSrs: (srs, program) =>
|
||||
defaultProvider.setupWithSrs(srs, program, options),
|
||||
generateProof: (program, witness, provingKey, entropy) =>
|
||||
defaultProvider.generateProof(
|
||||
program,
|
||||
witness,
|
||||
provingKey,
|
||||
entropy,
|
||||
options
|
||||
),
|
||||
verify: (vk, proof) => defaultProvider.verify(vk, proof, options),
|
||||
exportSolidityVerifier: (vk) =>
|
||||
defaultProvider.exportSolidityVerifier(vk),
|
||||
utils: {
|
||||
formatProof: (proof) => defaultProvider.utils.formatProof(proof),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
return {
|
||||
...withOptions({ backend: "ark", scheme: "g16", curve: "bn128" }),
|
||||
};
|
||||
};
|
||||
|
||||
export { initialize, metadata };
|
||||
|
|
|
@ -1,112 +0,0 @@
|
|||
module.exports = (pkg) => {
|
||||
const defaultProvider = {
|
||||
compile: (source, compileOptions = {}) => {
|
||||
var {
|
||||
curve = "bn128",
|
||||
location = "main.zok",
|
||||
resolveCallback = () => null,
|
||||
config = {},
|
||||
snarkjs = false,
|
||||
} = compileOptions;
|
||||
|
||||
config = { snarkjs, ...config };
|
||||
|
||||
const ptr = pkg.compile(source, location, resolveCallback, config, curve);
|
||||
const result = Object.assign(
|
||||
{
|
||||
program: ptr.program(),
|
||||
abi: ptr.abi(),
|
||||
constraintCount: ptr.constraint_count(),
|
||||
},
|
||||
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, logCallback = console.log } = computeOptions;
|
||||
const ptr = pkg.compute_witness(
|
||||
program,
|
||||
abi,
|
||||
JSON.stringify(args),
|
||||
{
|
||||
snarkjs: snarkjs,
|
||||
},
|
||||
logCallback
|
||||
);
|
||||
|
||||
const result = Object.assign(
|
||||
{
|
||||
witness: ptr.witness(),
|
||||
output: ptr.output(),
|
||||
},
|
||||
snarkjs
|
||||
? {
|
||||
snarkjs: {
|
||||
witness: ptr.snarkjs_witness(),
|
||||
},
|
||||
}
|
||||
: {}
|
||||
);
|
||||
|
||||
ptr.free();
|
||||
return result;
|
||||
},
|
||||
setup: (program, options) => {
|
||||
return pkg.setup(program, options);
|
||||
},
|
||||
universalSetup: (curve, size) => {
|
||||
return pkg.universal_setup(curve, size);
|
||||
},
|
||||
setupWithSrs: (srs, program, options) => {
|
||||
return pkg.setup_with_srs(srs, program, options);
|
||||
},
|
||||
generateProof: (program, witness, provingKey, options) => {
|
||||
return pkg.generate_proof(program, witness, provingKey, options);
|
||||
},
|
||||
verify: (vk, proof, options) => {
|
||||
return pkg.verify(vk, proof, options);
|
||||
},
|
||||
exportSolidityVerifier: (vk) => {
|
||||
return pkg.export_solidity_verifier(vk);
|
||||
},
|
||||
utils: {
|
||||
formatProof: (proof) => {
|
||||
return pkg.format_proof(proof);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const withOptions = (options) => {
|
||||
return {
|
||||
withOptions,
|
||||
compile: (source, compileOptions = {}) =>
|
||||
defaultProvider.compile(source, {
|
||||
...compileOptions,
|
||||
curve: options.curve,
|
||||
}),
|
||||
computeWitness: (artifacts, args, computeOptions = {}) =>
|
||||
defaultProvider.computeWitness(artifacts, args, computeOptions),
|
||||
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),
|
||||
utils: {
|
||||
formatProof: (proof) => defaultProvider.utils.formatProof(proof),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
return {
|
||||
...withOptions({ backend: "ark", scheme: "g16", curve: "bn128" }),
|
||||
};
|
||||
};
|
|
@ -1,8 +0,0 @@
|
|||
const lib = require("../lib.js");
|
||||
const metadata = require("../metadata.js");
|
||||
|
||||
const initialize = async () => {
|
||||
return lib(require("./pkg/index.js"));
|
||||
};
|
||||
|
||||
module.exports = { initialize, metadata };
|
8133
zokrates_js/package-lock.json
generated
8133
zokrates_js/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "zokrates-js",
|
||||
"version": "1.1.4",
|
||||
"version": "1.1.5",
|
||||
"module": "index.js",
|
||||
"main": "node/index.js",
|
||||
"main": "index-node.js",
|
||||
"description": "JavaScript bindings for ZoKrates",
|
||||
"contributors": [
|
||||
"Darko Macesic <darem966@gmail.com>",
|
||||
|
@ -15,38 +15,46 @@
|
|||
],
|
||||
"license": "GPLv3",
|
||||
"files": [
|
||||
"node",
|
||||
"pkg",
|
||||
"index.js",
|
||||
"index-node.js",
|
||||
"index.d.ts",
|
||||
"lib.js",
|
||||
"metadata.js"
|
||||
"wasm.js",
|
||||
"metadata.js",
|
||||
"umd.min.js"
|
||||
],
|
||||
"types": "index.d.ts",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
"node": "./node/index.js",
|
||||
"node": "./index-node.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"scripts": {
|
||||
"wasm-pack": "wasm-pack build --out-name index",
|
||||
"wasm-pack": "wasm-pack build --out-name index --target web",
|
||||
"prebuild": "npm install",
|
||||
"build": "npm run build:bundler && npm run build:node",
|
||||
"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 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",
|
||||
"build": "npm run wasm-pack -- --release && npm run patch && npm run bundle",
|
||||
"build:dev": "npm run wasm-pack -- --dev && npm run patch && npm run bundle",
|
||||
"pretest": "npm run build:dev",
|
||||
"test": "npm run run-tests",
|
||||
"run-tests": "mocha --timeout 100000 --recursive tests"
|
||||
"run-tests": "mocha --timeout 100000 --recursive tests",
|
||||
"patch": "node patch.js",
|
||||
"bundle": "browserify ./index.js --standalone zokrates -t [ babelify --presets [ @babel/preset-env ] ] | uglifyjs --compress --mangle > umd.min.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"dree": "^2.6.1",
|
||||
"@babel/core": "^7.20.12",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"acorn": "^8.8.1",
|
||||
"astring": "^1.8.4",
|
||||
"babelify": "^10.0.0",
|
||||
"browserify": "^17.0.0",
|
||||
"dree": "^3.4.3",
|
||||
"mocha": "^9.2.0",
|
||||
"puppeteer": "^19.6.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"snarkjs": "^0.4.25",
|
||||
"uglify-js": "^3.17.4",
|
||||
"wasm-pack": "^0.10.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"pako": "^2.1.0"
|
||||
}
|
||||
}
|
||||
|
|
75
zokrates_js/patch.js
Normal file
75
zokrates_js/patch.js
Normal file
|
@ -0,0 +1,75 @@
|
|||
import { parse } from "acorn";
|
||||
import { generate } from "astring";
|
||||
import fs from "fs/promises";
|
||||
import pako from "pako";
|
||||
|
||||
(async function () {
|
||||
const packageObject = JSON.parse(
|
||||
await fs.readFile("pkg/package.json", { encoding: "utf-8" })
|
||||
);
|
||||
const wasmPath = packageObject.files.find((file) => file.endsWith(".wasm"));
|
||||
const wasm = await fs.readFile(`pkg/${wasmPath}`);
|
||||
|
||||
const deflated = Buffer.from(pako.deflate(wasm));
|
||||
const wasmBase64 = deflated.toString("base64");
|
||||
|
||||
const init = `export async function init(inflate) {
|
||||
const encoded = '${wasmBase64}';
|
||||
|
||||
let bytes;
|
||||
|
||||
if (typeof Buffer === "function") {
|
||||
bytes = Buffer.from(encoded, "base64");
|
||||
} else if (typeof atob === "function") {
|
||||
const binary = atob(encoded);
|
||||
bytes = new Uint8Array(binary.length);
|
||||
|
||||
for (let i = 0; i < binary.length; i++) {
|
||||
bytes[i] = binary.charCodeAt(i);
|
||||
}
|
||||
} else {
|
||||
throw new Error("Unsupported platform");
|
||||
}
|
||||
|
||||
const imports = getImports();
|
||||
initMemory(imports);
|
||||
|
||||
bytes = inflate(bytes);
|
||||
|
||||
const { instance, module } = await WebAssembly.instantiate(bytes, imports);
|
||||
return finalizeInit(instance, module);
|
||||
}
|
||||
|
||||
export default init;`;
|
||||
|
||||
const generatedSource = await fs.readFile(`pkg/${packageObject.module}`, {
|
||||
encoding: "utf-8",
|
||||
});
|
||||
|
||||
const ast = parse(generatedSource, {
|
||||
ecmaVersion: "latest",
|
||||
sourceType: "module",
|
||||
});
|
||||
|
||||
let body = ast.body.filter((v) => {
|
||||
switch (v.type) {
|
||||
case "FunctionDeclaration":
|
||||
// we don't use these functions so we strip them out
|
||||
return !["load", "init", "initSync"].includes(v.id.name);
|
||||
case "ExportDefaultDeclaration":
|
||||
// we will provide our own default export
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
body.pop(); // removes `export { initSync }`
|
||||
|
||||
const source = generate({
|
||||
...ast,
|
||||
body,
|
||||
});
|
||||
|
||||
await fs.writeFile("wasm.js", source + init);
|
||||
})();
|
|
@ -24,12 +24,6 @@ if [ $NPM_VERSION = $PACKAGE_VERSION ]; then
|
|||
exit 0
|
||||
fi
|
||||
|
||||
# make sure the pkg folder is present
|
||||
if [ ! -d "pkg" ]; then
|
||||
echo "pkg folder is missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# publish
|
||||
npm set //registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
npm publish
|
|
@ -4,6 +4,7 @@ mod util;
|
|||
extern crate lazy_static;
|
||||
|
||||
use crate::util::normalize_path;
|
||||
use rand_0_8::{rngs::StdRng, SeedableRng};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::to_string_pretty;
|
||||
use std::convert::TryFrom;
|
||||
|
@ -25,6 +26,7 @@ use zokrates_core::compile::{compile as core_compile, CompilationArtifacts, Comp
|
|||
use zokrates_core::imports::Error;
|
||||
use zokrates_field::{Bls12_377Field, Bls12_381Field, Bn128Field, Bw6_761Field, Field};
|
||||
use zokrates_proof_systems::groth16::G16;
|
||||
use zokrates_proof_systems::rng::get_rng_from_entropy;
|
||||
use zokrates_proof_systems::{
|
||||
Backend, Marlin, NonUniversalBackend, NonUniversalScheme, Proof, Scheme,
|
||||
SolidityCompatibleField, SolidityCompatibleScheme, TaggedKeypair, TaggedProof,
|
||||
|
@ -220,6 +222,7 @@ impl<'a> Write for LogWriter<'a> {
|
|||
|
||||
mod internal {
|
||||
use super::*;
|
||||
use rand_0_8::{CryptoRng, RngCore};
|
||||
|
||||
pub fn compile<T: Field>(
|
||||
source: JsValue,
|
||||
|
@ -345,10 +348,12 @@ mod internal {
|
|||
T: Field,
|
||||
S: NonUniversalScheme<T> + Serialize,
|
||||
B: NonUniversalBackend<T, S>,
|
||||
R: RngCore + CryptoRng,
|
||||
>(
|
||||
program: ir::Prog<T>,
|
||||
rng: &mut R,
|
||||
) -> JsValue {
|
||||
let keypair = B::setup(program);
|
||||
let keypair = B::setup(program, rng);
|
||||
let tagged_keypair = TaggedKeypair::<T, S>::new(keypair);
|
||||
JsValue::from_serde(&tagged_keypair).unwrap()
|
||||
}
|
||||
|
@ -367,22 +372,29 @@ mod internal {
|
|||
Ok(JsValue::from_serde(&TaggedKeypair::<T, S>::new(keypair)).unwrap())
|
||||
}
|
||||
|
||||
pub fn universal_setup_of_size<T: Field, S: UniversalScheme<T>, B: UniversalBackend<T, S>>(
|
||||
pub fn universal_setup_of_size<
|
||||
T: Field,
|
||||
S: UniversalScheme<T>,
|
||||
B: UniversalBackend<T, S>,
|
||||
R: RngCore + CryptoRng,
|
||||
>(
|
||||
size: u32,
|
||||
rng: &mut R,
|
||||
) -> Vec<u8> {
|
||||
B::universal_setup(size)
|
||||
B::universal_setup(size, rng)
|
||||
}
|
||||
|
||||
pub fn generate_proof<T: Field, S: Scheme<T>, B: Backend<T, S>>(
|
||||
pub fn generate_proof<T: Field, S: Scheme<T>, B: Backend<T, S>, R: RngCore + CryptoRng>(
|
||||
prog: ir::Prog<T>,
|
||||
witness: JsValue,
|
||||
pk: &[u8],
|
||||
rng: &mut R,
|
||||
) -> Result<JsValue, JsValue> {
|
||||
let str_witness = witness.as_string().unwrap();
|
||||
let ir_witness: ir::Witness<T> = ir::Witness::read(str_witness.as_bytes())
|
||||
.map_err(|err| JsValue::from_str(&format!("Could not read witness: {}", err)))?;
|
||||
|
||||
let proof = B::generate_proof(prog, ir_witness, pk.to_vec());
|
||||
let proof = B::generate_proof(prog, ir_witness, pk.to_vec(), rng);
|
||||
Ok(JsValue::from_serde(&TaggedProof::<T, S>::new(proof.proof, proof.inputs)).unwrap())
|
||||
}
|
||||
|
||||
|
@ -517,7 +529,7 @@ pub fn export_solidity_verifier(vk: JsValue) -> Result<JsValue, JsValue> {
|
|||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn setup(program: &[u8], options: JsValue) -> Result<JsValue, JsValue> {
|
||||
pub fn setup(program: &[u8], entropy: JsValue, options: JsValue) -> Result<JsValue, JsValue> {
|
||||
let options: serde_json::Value = options.into_serde().unwrap();
|
||||
|
||||
let backend = BackendParameter::try_from(
|
||||
|
@ -539,25 +551,48 @@ pub fn setup(program: &[u8], options: JsValue) -> Result<JsValue, JsValue> {
|
|||
.map_err(|err| JsValue::from_str(&err))?
|
||||
.collect();
|
||||
|
||||
let mut rng = entropy
|
||||
.as_string()
|
||||
.map(|s| get_rng_from_entropy(&s))
|
||||
.unwrap_or_else(StdRng::from_entropy);
|
||||
|
||||
match (backend, scheme) {
|
||||
(BackendParameter::Bellman, SchemeParameter::G16) => match prog {
|
||||
ProgEnum::Bn128Program(p) => Ok(internal::setup_non_universal::<_, G16, Bellman>(p)),
|
||||
ProgEnum::Bn128Program(p) => Ok(internal::setup_non_universal::<_, G16, Bellman, _>(
|
||||
p, &mut rng,
|
||||
)),
|
||||
ProgEnum::Bls12_381Program(_) => Err(JsValue::from_str(
|
||||
"Not supported: https://github.com/Zokrates/ZoKrates/issues/1200",
|
||||
)),
|
||||
_ => Err(JsValue::from_str("Not supported")),
|
||||
},
|
||||
(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)),
|
||||
ProgEnum::Bn128Program(p) => {
|
||||
Ok(internal::setup_non_universal::<_, G16, Ark, _>(p, &mut rng))
|
||||
}
|
||||
ProgEnum::Bls12_381Program(p) => {
|
||||
Ok(internal::setup_non_universal::<_, G16, Ark, _>(p, &mut rng))
|
||||
}
|
||||
ProgEnum::Bls12_377Program(p) => {
|
||||
Ok(internal::setup_non_universal::<_, G16, Ark, _>(p, &mut rng))
|
||||
}
|
||||
ProgEnum::Bw6_761Program(p) => {
|
||||
Ok(internal::setup_non_universal::<_, G16, Ark, _>(p, &mut rng))
|
||||
}
|
||||
},
|
||||
(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)),
|
||||
ProgEnum::Bn128Program(p) => Ok(internal::setup_non_universal::<_, GM17, Ark, _>(
|
||||
p, &mut rng,
|
||||
)),
|
||||
ProgEnum::Bls12_381Program(p) => Ok(internal::setup_non_universal::<_, GM17, Ark, _>(
|
||||
p, &mut rng,
|
||||
)),
|
||||
ProgEnum::Bls12_377Program(p) => Ok(internal::setup_non_universal::<_, GM17, Ark, _>(
|
||||
p, &mut rng,
|
||||
)),
|
||||
ProgEnum::Bw6_761Program(p) => Ok(internal::setup_non_universal::<_, GM17, Ark, _>(
|
||||
p, &mut rng,
|
||||
)),
|
||||
},
|
||||
_ => Err(JsValue::from_str("Unsupported options")),
|
||||
}
|
||||
|
@ -591,27 +626,40 @@ pub fn setup_with_srs(srs: &[u8], program: &[u8], options: JsValue) -> Result<Js
|
|||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn universal_setup(curve: JsValue, size: u32) -> Result<Vec<u8>, JsValue> {
|
||||
pub fn universal_setup(curve: JsValue, size: u32, entropy: JsValue) -> Result<Vec<u8>, JsValue> {
|
||||
let curve = CurveParameter::try_from(curve.as_string().unwrap().as_str())
|
||||
.map_err(|e| JsValue::from_str(&e))?;
|
||||
|
||||
let mut rng = entropy
|
||||
.as_string()
|
||||
.map(|s| get_rng_from_entropy(&s))
|
||||
.unwrap_or_else(StdRng::from_entropy);
|
||||
|
||||
match curve {
|
||||
CurveParameter::Bn128 => {
|
||||
Ok(internal::universal_setup_of_size::<Bn128Field, Marlin, Ark>(size))
|
||||
}
|
||||
CurveParameter::Bn128 => Ok(internal::universal_setup_of_size::<
|
||||
Bn128Field,
|
||||
Marlin,
|
||||
Ark,
|
||||
_,
|
||||
>(size, &mut rng)),
|
||||
CurveParameter::Bls12_381 => Ok(internal::universal_setup_of_size::<
|
||||
Bls12_381Field,
|
||||
Marlin,
|
||||
Ark,
|
||||
>(size)),
|
||||
_,
|
||||
>(size, &mut rng)),
|
||||
CurveParameter::Bls12_377 => Ok(internal::universal_setup_of_size::<
|
||||
Bls12_377Field,
|
||||
Marlin,
|
||||
Ark,
|
||||
>(size)),
|
||||
CurveParameter::Bw6_761 => {
|
||||
Ok(internal::universal_setup_of_size::<Bw6_761Field, Marlin, Ark>(size))
|
||||
}
|
||||
_,
|
||||
>(size, &mut rng)),
|
||||
CurveParameter::Bw6_761 => Ok(internal::universal_setup_of_size::<
|
||||
Bw6_761Field,
|
||||
Marlin,
|
||||
Ark,
|
||||
_,
|
||||
>(size, &mut rng)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -620,6 +668,7 @@ pub fn generate_proof(
|
|||
program: &[u8],
|
||||
witness: JsValue,
|
||||
pk: &[u8],
|
||||
entropy: JsValue,
|
||||
options: JsValue,
|
||||
) -> Result<JsValue, JsValue> {
|
||||
let options: serde_json::Value = options.into_serde().unwrap();
|
||||
|
@ -643,10 +692,15 @@ pub fn generate_proof(
|
|||
.map_err(|err| JsValue::from_str(&err))?
|
||||
.collect();
|
||||
|
||||
let mut rng = entropy
|
||||
.as_string()
|
||||
.map(|s| get_rng_from_entropy(&s))
|
||||
.unwrap_or_else(StdRng::from_entropy);
|
||||
|
||||
match (backend, scheme) {
|
||||
(BackendParameter::Bellman, SchemeParameter::G16) => match prog {
|
||||
ProgEnum::Bn128Program(p) => {
|
||||
internal::generate_proof::<_, G16, Bellman>(p, witness, pk)
|
||||
internal::generate_proof::<_, G16, Bellman, _>(p, witness, pk, &mut rng)
|
||||
}
|
||||
ProgEnum::Bls12_381Program(_) => Err(JsValue::from_str(
|
||||
"Not supported: https://github.com/Zokrates/ZoKrates/issues/1200",
|
||||
|
@ -654,35 +708,45 @@ pub fn generate_proof(
|
|||
_ => Err(JsValue::from_str("Not supported")),
|
||||
},
|
||||
(BackendParameter::Ark, SchemeParameter::G16) => match prog {
|
||||
ProgEnum::Bn128Program(p) => internal::generate_proof::<_, G16, Ark>(p, witness, pk),
|
||||
ProgEnum::Bn128Program(p) => {
|
||||
internal::generate_proof::<_, G16, Ark, _>(p, witness, pk, &mut rng)
|
||||
}
|
||||
ProgEnum::Bls12_381Program(p) => {
|
||||
internal::generate_proof::<_, G16, Ark>(p, witness, pk)
|
||||
internal::generate_proof::<_, G16, Ark, _>(p, witness, pk, &mut rng)
|
||||
}
|
||||
ProgEnum::Bls12_377Program(p) => {
|
||||
internal::generate_proof::<_, G16, Ark>(p, witness, pk)
|
||||
}
|
||||
ProgEnum::Bw6_761Program(p) => internal::generate_proof::<_, G16, Ark>(p, witness, pk),
|
||||
},
|
||||
(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)
|
||||
}
|
||||
ProgEnum::Bls12_377Program(p) => {
|
||||
internal::generate_proof::<_, GM17, Ark>(p, witness, pk)
|
||||
}
|
||||
ProgEnum::Bw6_761Program(p) => internal::generate_proof::<_, GM17, Ark>(p, witness, pk),
|
||||
},
|
||||
(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)
|
||||
}
|
||||
ProgEnum::Bls12_377Program(p) => {
|
||||
internal::generate_proof::<_, Marlin, Ark>(p, witness, pk)
|
||||
internal::generate_proof::<_, G16, Ark, _>(p, witness, pk, &mut rng)
|
||||
}
|
||||
ProgEnum::Bw6_761Program(p) => {
|
||||
internal::generate_proof::<_, Marlin, Ark>(p, witness, pk)
|
||||
internal::generate_proof::<_, G16, Ark, _>(p, witness, pk, &mut rng)
|
||||
}
|
||||
},
|
||||
(BackendParameter::Ark, SchemeParameter::GM17) => match prog {
|
||||
ProgEnum::Bn128Program(p) => {
|
||||
internal::generate_proof::<_, GM17, Ark, _>(p, witness, pk, &mut rng)
|
||||
}
|
||||
ProgEnum::Bls12_381Program(p) => {
|
||||
internal::generate_proof::<_, GM17, Ark, _>(p, witness, pk, &mut rng)
|
||||
}
|
||||
ProgEnum::Bls12_377Program(p) => {
|
||||
internal::generate_proof::<_, GM17, Ark, _>(p, witness, pk, &mut rng)
|
||||
}
|
||||
ProgEnum::Bw6_761Program(p) => {
|
||||
internal::generate_proof::<_, GM17, Ark, _>(p, witness, pk, &mut rng)
|
||||
}
|
||||
},
|
||||
(BackendParameter::Ark, SchemeParameter::MARLIN) => match prog {
|
||||
ProgEnum::Bn128Program(p) => {
|
||||
internal::generate_proof::<_, Marlin, Ark, _>(p, witness, pk, &mut rng)
|
||||
}
|
||||
ProgEnum::Bls12_381Program(p) => {
|
||||
internal::generate_proof::<_, Marlin, Ark, _>(p, witness, pk, &mut rng)
|
||||
}
|
||||
ProgEnum::Bls12_377Program(p) => {
|
||||
internal::generate_proof::<_, Marlin, Ark, _>(p, witness, pk, &mut rng)
|
||||
}
|
||||
ProgEnum::Bw6_761Program(p) => {
|
||||
internal::generate_proof::<_, Marlin, Ark, _>(p, witness, pk, &mut rng)
|
||||
}
|
||||
},
|
||||
_ => Err(JsValue::from_str("Unsupported options")),
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
const assert = require("assert");
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const os = require("os");
|
||||
const dree = require("dree");
|
||||
const snarkjs = require("snarkjs");
|
||||
const { initialize, metadata } = require("../node/index.js");
|
||||
import assert from "assert";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import os from "os";
|
||||
import * as snarkjs from "snarkjs";
|
||||
import dree from "dree";
|
||||
import { initialize, metadata } from "../index-node.js";
|
||||
|
||||
let zokratesProvider;
|
||||
let tmpFolder;
|
||||
|
@ -38,25 +38,21 @@ describe("tests", () => {
|
|||
|
||||
describe("compilation", () => {
|
||||
it("should compile", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
const artifacts = zokratesProvider.compile(
|
||||
"def main() -> field { return 42; }"
|
||||
);
|
||||
assert.ok(artifacts);
|
||||
assert.ok(artifacts.snarkjs === undefined);
|
||||
assert.equal(artifacts.constraintCount, 1);
|
||||
});
|
||||
const artifacts = zokratesProvider.compile(
|
||||
"def main() -> field { return 42; }"
|
||||
);
|
||||
assert.ok(artifacts);
|
||||
assert.ok(artifacts.snarkjs === undefined);
|
||||
assert.equal(artifacts.constraintCount, 1);
|
||||
});
|
||||
|
||||
it("should compile with snarkjs output", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
const artifacts = zokratesProvider.compile(
|
||||
"def main() -> field { return 42; }",
|
||||
{ snarkjs: true }
|
||||
);
|
||||
assert.ok(artifacts);
|
||||
assert.ok(artifacts.snarkjs.program !== undefined);
|
||||
});
|
||||
const artifacts = zokratesProvider.compile(
|
||||
"def main() -> field { return 42; }",
|
||||
{ snarkjs: true }
|
||||
);
|
||||
assert.ok(artifacts);
|
||||
assert.ok(artifacts.snarkjs.program !== undefined);
|
||||
});
|
||||
|
||||
it("should throw on invalid code", () => {
|
||||
|
@ -64,26 +60,22 @@ describe("tests", () => {
|
|||
});
|
||||
|
||||
it("should resolve stdlib module", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
const code = `import "utils/pack/bool/unpack" as unpack;\ndef main() { return; }`;
|
||||
zokratesProvider.compile(code);
|
||||
});
|
||||
const code = `import "utils/pack/bool/unpack_unchecked";\ndef main() {}`;
|
||||
zokratesProvider.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,
|
||||
};
|
||||
},
|
||||
};
|
||||
zokratesProvider.compile(code, options);
|
||||
});
|
||||
const code =
|
||||
'import "./test" as test;\ndef main() -> field { return test(); }';
|
||||
const options = {
|
||||
resolveCallback: (_, path) => {
|
||||
return {
|
||||
source: "def main() -> field { return 1; }",
|
||||
location: path,
|
||||
};
|
||||
},
|
||||
};
|
||||
zokratesProvider.compile(code, options);
|
||||
});
|
||||
|
||||
it("should throw on unresolved module", () => {
|
||||
|
@ -97,29 +89,25 @@ describe("tests", () => {
|
|||
|
||||
describe("computation", () => {
|
||||
it("should compute with valid inputs", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
const code = "def main(private field a) -> field { return a * a; }";
|
||||
const artifacts = zokratesProvider.compile(code);
|
||||
const result = zokratesProvider.computeWitness(artifacts, ["2"]);
|
||||
const output = JSON.parse(result.output);
|
||||
assert.deepEqual(output, "4");
|
||||
assert.ok(result.snarkjs === undefined);
|
||||
});
|
||||
const code = "def main(private field a) -> field { return a * a; }";
|
||||
const artifacts = zokratesProvider.compile(code);
|
||||
const result = zokratesProvider.computeWitness(artifacts, ["2"]);
|
||||
const output = JSON.parse(result.output);
|
||||
assert.deepEqual(output, "4");
|
||||
assert.ok(result.snarkjs === undefined);
|
||||
});
|
||||
|
||||
it("should compute with valid inputs with snarkjs output", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
const code = "def main(private field a) -> field { return a * a; }";
|
||||
const artifacts = zokratesProvider.compile(code);
|
||||
const code = "def main(private field a) -> field { return a * a; }";
|
||||
const artifacts = zokratesProvider.compile(code);
|
||||
|
||||
const result = zokratesProvider.computeWitness(artifacts, ["2"], {
|
||||
snarkjs: true,
|
||||
});
|
||||
|
||||
const output = JSON.parse(result.output);
|
||||
assert.deepEqual(output, "4");
|
||||
assert.ok(result.snarkjs.witness !== undefined);
|
||||
const result = zokratesProvider.computeWitness(artifacts, ["2"], {
|
||||
snarkjs: true,
|
||||
});
|
||||
|
||||
const output = JSON.parse(result.output);
|
||||
assert.deepEqual(output, "4");
|
||||
assert.ok(result.snarkjs.witness !== undefined);
|
||||
});
|
||||
|
||||
it("should throw on invalid input count", () => {
|
||||
|
@ -139,19 +127,17 @@ describe("tests", () => {
|
|||
});
|
||||
|
||||
it("should log in debug", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
const code = 'def main() { log("{}", 1f); log("{}", 2f); return; }';
|
||||
const artifacts = zokratesProvider.compile(code, {
|
||||
config: { debug: true },
|
||||
});
|
||||
let logs = [];
|
||||
zokratesProvider.computeWitness(artifacts, [], {
|
||||
logCallback: (l) => {
|
||||
logs.push(l);
|
||||
},
|
||||
});
|
||||
assert.deepEqual(logs, ['"1"', '"2"']);
|
||||
const code = 'def main() { log("{}", 1f); log("{}", 2f); return; }';
|
||||
const artifacts = zokratesProvider.compile(code, {
|
||||
config: { debug: true },
|
||||
});
|
||||
let logs = [];
|
||||
zokratesProvider.computeWitness(artifacts, [], {
|
||||
logCallback: (l) => {
|
||||
logs.push(l);
|
||||
},
|
||||
});
|
||||
assert.deepEqual(logs, ['"1"', '"2"']);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -167,37 +153,53 @@ describe("tests", () => {
|
|||
});
|
||||
|
||||
it("compile", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
const code = `def main(private field a, field b) -> bool {
|
||||
bool check = if (a == 0){ true} else {a * a == b};
|
||||
assert(check);
|
||||
return true;
|
||||
}`;
|
||||
artifacts = provider.compile(code, { snarkjs: true });
|
||||
});
|
||||
const code = `def main(private field a, field b) -> bool {
|
||||
bool check = if (a == 0) { true } else { a * a == b };
|
||||
assert(check);
|
||||
return true;
|
||||
}`;
|
||||
artifacts = provider.compile(code, { snarkjs: true });
|
||||
});
|
||||
|
||||
it("compute witness", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
computationResult = provider.computeWitness(
|
||||
artifacts,
|
||||
["337", "113569"],
|
||||
{
|
||||
snarkjs: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
computationResult = provider.computeWitness(
|
||||
artifacts,
|
||||
["337", "113569"],
|
||||
{
|
||||
snarkjs: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it("setup", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
if (options.scheme === "marlin") {
|
||||
const srs = provider.universalSetup(4);
|
||||
keypair = provider.setupWithSrs(srs, artifacts.program);
|
||||
} else {
|
||||
keypair = provider.setup(artifacts.program);
|
||||
}
|
||||
});
|
||||
if (options.scheme === "marlin") {
|
||||
const srs = provider.universalSetup(4);
|
||||
const srs2 = provider.universalSetup(4);
|
||||
// second call should return a new srs
|
||||
assert.notDeepEqual(srs, srs2);
|
||||
keypair = provider.setupWithSrs(srs, artifacts.program);
|
||||
} else {
|
||||
keypair = provider.setup(artifacts.program);
|
||||
const keypair2 = provider.setup(artifacts.program);
|
||||
// second call should return a new keypair
|
||||
assert.notDeepEqual(keypair, keypair2);
|
||||
}
|
||||
});
|
||||
|
||||
it("setup with user-provided entropy", () => {
|
||||
let entropy = "f5c51ca46c331965";
|
||||
if (options.scheme === "marlin") {
|
||||
const srs = provider.universalSetup(4, entropy);
|
||||
const srs2 = provider.universalSetup(4, entropy);
|
||||
// second call with the same entropy should return the same srs
|
||||
assert.deepEqual(srs, srs2);
|
||||
keypair = provider.setupWithSrs(srs, artifacts.program);
|
||||
} else {
|
||||
keypair = provider.setup(artifacts.program, entropy);
|
||||
const keypair2 = provider.setup(artifacts.program, entropy);
|
||||
// second call with the same entropy should return the same keypair
|
||||
assert.deepEqual(keypair, keypair2);
|
||||
}
|
||||
});
|
||||
|
||||
if (options.scheme === "g16" && options.curve == "bn128") {
|
||||
|
@ -220,23 +222,48 @@ describe("tests", () => {
|
|||
|
||||
if (options.curve === "bn128" && ["g16", "gm17"].includes(options.scheme)) {
|
||||
it("export verifier", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
let verifier = provider.exportSolidityVerifier(keypair.vk);
|
||||
assert.ok(verifier.includes("contract"));
|
||||
});
|
||||
let verifier = provider.exportSolidityVerifier(keypair.vk);
|
||||
assert.ok(verifier.includes("contract"));
|
||||
});
|
||||
}
|
||||
|
||||
it("generate proof", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
proof = provider.generateProof(
|
||||
artifacts.program,
|
||||
computationResult.witness,
|
||||
keypair.pk
|
||||
);
|
||||
assert.ok(proof !== undefined);
|
||||
assert.equal(proof.inputs.length, 2);
|
||||
});
|
||||
proof = provider.generateProof(
|
||||
artifacts.program,
|
||||
computationResult.witness,
|
||||
keypair.pk
|
||||
);
|
||||
assert.ok(proof !== undefined);
|
||||
assert.equal(proof.inputs.length, 2);
|
||||
|
||||
// second call should return a new proof
|
||||
let proof2 = provider.generateProof(
|
||||
artifacts.program,
|
||||
computationResult.witness,
|
||||
keypair.pk
|
||||
);
|
||||
assert.notDeepEqual(proof, proof2);
|
||||
});
|
||||
|
||||
it("generate proof with user-provided entropy", () => {
|
||||
let entropy = "326e2c864f414ffb";
|
||||
proof = provider.generateProof(
|
||||
artifacts.program,
|
||||
computationResult.witness,
|
||||
keypair.pk,
|
||||
entropy
|
||||
);
|
||||
assert.ok(proof !== undefined);
|
||||
assert.equal(proof.inputs.length, 2);
|
||||
|
||||
// second call with the same entropy should return the same proof
|
||||
let proof2 = provider.generateProof(
|
||||
artifacts.program,
|
||||
computationResult.witness,
|
||||
keypair.pk,
|
||||
entropy
|
||||
);
|
||||
assert.deepEqual(proof, proof2);
|
||||
});
|
||||
|
||||
if (options.scheme === "g16" && options.curve == "bn128") {
|
||||
|
@ -264,9 +291,7 @@ describe("tests", () => {
|
|||
}
|
||||
|
||||
it("verify", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
assert(provider.verify(keypair.vk, proof) === true);
|
||||
});
|
||||
assert(provider.verify(keypair.vk, proof) === true);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -364,8 +389,8 @@ describe("tests", () => {
|
|||
extensions: ["json"],
|
||||
};
|
||||
|
||||
dree.scan(testsPath, options, function (file) {
|
||||
const test = require(file.path);
|
||||
dree.scan(testsPath, options, async function (file) {
|
||||
const test = JSON.parse(await fs.promises.readFile(file.path));
|
||||
const testName = file.path.substring(testsPath.length + 1);
|
||||
|
||||
if (!ignoreList.some((v) => testName.startsWith(v)))
|
||||
|
|
38
zokrates_js/tests/umd/index.html
Normal file
38
zokrates_js/tests/umd/index.html
Normal file
|
@ -0,0 +1,38 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Test Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="../../umd.min.js"></script>
|
||||
<script>
|
||||
zokrates.initialize().then((zokratesProvider) => {
|
||||
const source = "def main(private field a) -> field { return a * a; }";
|
||||
|
||||
const artifacts = zokratesProvider.compile(source);
|
||||
const { witness, output } = zokratesProvider.computeWitness(artifacts, [
|
||||
"2",
|
||||
]);
|
||||
|
||||
const keypair = zokratesProvider.setup(artifacts.program);
|
||||
|
||||
const proof = zokratesProvider.generateProof(
|
||||
artifacts.program,
|
||||
witness,
|
||||
keypair.pk
|
||||
);
|
||||
|
||||
const isVerified = zokratesProvider.verify(keypair.vk, proof);
|
||||
|
||||
var result = document.createElement("div");
|
||||
result.id = "result";
|
||||
result.innerText = isVerified;
|
||||
|
||||
document.body.appendChild(result);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
27
zokrates_js/tests/umd/tests.js
Normal file
27
zokrates_js/tests/umd/tests.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
import puppeteer from "puppeteer";
|
||||
import assert from "assert";
|
||||
import path from "path";
|
||||
|
||||
describe("umd web tests", () => {
|
||||
it("verify", async () => {
|
||||
const browser = await puppeteer.launch({
|
||||
headless: true,
|
||||
args: ["--no-sandbox", "--disable-setuid-sandbox"],
|
||||
});
|
||||
const page = await browser.newPage();
|
||||
|
||||
let response = await page.goto(
|
||||
path.dirname(import.meta.url) + "/index.html"
|
||||
);
|
||||
assert(response.ok());
|
||||
|
||||
let element = await page.waitForSelector("#result", {
|
||||
timeout: 30000,
|
||||
visible: true,
|
||||
});
|
||||
let value = await element.evaluate((el) => el.textContent, element);
|
||||
assert.equal(value, "true");
|
||||
|
||||
await browser.close();
|
||||
});
|
||||
});
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_parser"
|
||||
version = "0.3.2"
|
||||
version = "0.3.3"
|
||||
authors = ["JacobEberhardt <jacob.eberhardt@tu-berlin.de>"]
|
||||
edition = "2018"
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_pest_ast"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
authors = ["schaeff <thibaut@schaeff.fr>"]
|
||||
edition = "2018"
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_proof_systems"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
@ -12,5 +12,6 @@ regex = "0.2"
|
|||
cfg-if = "0.1"
|
||||
ethabi = "17.0.0"
|
||||
primitive-types = { version = "0.11", features = ["rlp"] }
|
||||
rand_0_4 = { version = "0.4", package = "rand" }
|
||||
getrandom = { version = "0.2", features = ["js"] }
|
||||
rand_0_8 = { version = "0.8", package = "rand" }
|
||||
blake2 = "0.8.1"
|
||||
byteorder = "1"
|
|
@ -1,3 +1,4 @@
|
|||
pub mod rng;
|
||||
pub mod to_token;
|
||||
|
||||
mod scheme;
|
||||
|
@ -10,9 +11,8 @@ pub use tagged::{TaggedKeypair, TaggedProof, TaggedVerificationKey};
|
|||
|
||||
use zokrates_ast::ir;
|
||||
|
||||
use rand_0_8::{CryptoRng, RngCore};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use rand_0_4::Rng;
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use zokrates_field::Field;
|
||||
|
@ -96,22 +96,24 @@ impl ToString for G2AffineFq2 {
|
|||
}
|
||||
|
||||
pub trait Backend<T: Field, S: Scheme<T>> {
|
||||
fn generate_proof<'a, I: IntoIterator<Item = ir::Statement<'a, T>>>(
|
||||
fn generate_proof<'a, I: IntoIterator<Item = ir::Statement<'a, T>>, R: RngCore + CryptoRng>(
|
||||
program: ir::ProgIterator<'a, T, I>,
|
||||
witness: ir::Witness<T>,
|
||||
proving_key: Vec<u8>,
|
||||
rng: &mut R,
|
||||
) -> Proof<T, S>;
|
||||
|
||||
fn verify(vk: S::VerificationKey, proof: Proof<T, S>) -> bool;
|
||||
}
|
||||
pub trait NonUniversalBackend<T: Field, S: NonUniversalScheme<T>>: Backend<T, S> {
|
||||
fn setup<'a, I: IntoIterator<Item = ir::Statement<'a, T>>>(
|
||||
fn setup<'a, I: IntoIterator<Item = ir::Statement<'a, T>>, R: RngCore + CryptoRng>(
|
||||
program: ir::ProgIterator<'a, T, I>,
|
||||
rng: &mut R,
|
||||
) -> SetupKeypair<T, S>;
|
||||
}
|
||||
|
||||
pub trait UniversalBackend<T: Field, S: UniversalScheme<T>>: Backend<T, S> {
|
||||
fn universal_setup(size: u32) -> Vec<u8>;
|
||||
fn universal_setup<R: RngCore + CryptoRng>(size: u32, rng: &mut R) -> Vec<u8>;
|
||||
|
||||
fn setup<'a, I: IntoIterator<Item = ir::Statement<'a, T>>>(
|
||||
srs: Vec<u8>,
|
||||
|
@ -126,7 +128,7 @@ pub trait MpcBackend<T: Field, S: Scheme<T>> {
|
|||
output: &mut W,
|
||||
) -> Result<(), String>;
|
||||
|
||||
fn contribute<R: Read, W: Write, G: Rng>(
|
||||
fn contribute<R: Read, W: Write, G: RngCore + CryptoRng>(
|
||||
params: &mut R,
|
||||
rng: &mut G,
|
||||
output: &mut W,
|
||||
|
|
20
zokrates_proof_systems/src/rng.rs
Normal file
20
zokrates_proof_systems/src/rng.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
use blake2::{Blake2b, Digest};
|
||||
use byteorder::ReadBytesExt;
|
||||
use rand_0_8::{rngs::StdRng, SeedableRng};
|
||||
|
||||
pub fn get_rng_from_entropy(entropy: &str) -> StdRng {
|
||||
let h = {
|
||||
let mut h = Blake2b::default();
|
||||
h.input(&entropy.as_bytes());
|
||||
h.result()
|
||||
};
|
||||
|
||||
let mut digest = &h[..];
|
||||
let mut seed = [0u8; 32];
|
||||
|
||||
for e in &mut seed {
|
||||
*e = digest.read_u8().unwrap();
|
||||
}
|
||||
|
||||
StdRng::from_seed(seed)
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
[package]
|
||||
name = "zokrates_solidity_test"
|
||||
version = "0.1.1"
|
||||
authors = ["Nirvan Tyagi <nirvan.tyagi@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# Modeled after the testing pipeline of the Fe project: https://github.com/ethereum/fe/
|
||||
|
||||
[dependencies]
|
||||
ethabi = "17.0.0"
|
||||
primitive-types = { version = "0.11", features = ["rlp"] }
|
||||
hex = { version = "0.4" }
|
||||
bytes = { version = "1.1", default-features = false }
|
||||
serde_json = { version = "1.0" }
|
||||
rand = { version = "0.8" }
|
||||
|
||||
revm = { version = "1.6.0" }
|
||||
solc = { git = "https://github.com/g-r-a-n-t/solc-rust", rev = "52d4146" }
|
|
@ -1,18 +0,0 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.10;
|
||||
|
||||
contract SimpleStorage {
|
||||
Var myVariable;
|
||||
|
||||
struct Var {
|
||||
uint v;
|
||||
}
|
||||
|
||||
function set(Var memory x) public {
|
||||
myVariable = x;
|
||||
}
|
||||
|
||||
function get() public view returns (uint) {
|
||||
return myVariable.v;
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
use ethabi::token::Token;
|
||||
use primitive_types::H160;
|
||||
use rand::Rng;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct Address(pub H160);
|
||||
|
||||
impl Address {
|
||||
pub fn random<R: Rng>(rng: &mut R) -> Self {
|
||||
Self(H160(rng.gen()))
|
||||
}
|
||||
|
||||
pub fn as_token(&self) -> Token {
|
||||
Token::Address(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<H160> for Address {
|
||||
fn as_ref(&self) -> &H160 {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<H160> for Address {
|
||||
fn from(hash: H160) -> Self {
|
||||
Self(hash)
|
||||
}
|
||||
}
|
|
@ -1,156 +0,0 @@
|
|||
use ethabi::{Contract as ContractAbi, Token};
|
||||
use serde_json::{from_str, json};
|
||||
use solc::compile;
|
||||
|
||||
use std::{fs::File, io::Read, path::Path};
|
||||
|
||||
use crate::{Error, EvmTestError};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Contract {
|
||||
pub binary: Vec<u8>,
|
||||
pub abi: ContractAbi,
|
||||
}
|
||||
|
||||
impl Contract {
|
||||
pub fn new(binary: Vec<u8>, abi: ContractAbi) -> Self {
|
||||
Self { binary, abi }
|
||||
}
|
||||
|
||||
pub fn compile_from_solidity_file<P: AsRef<Path>>(
|
||||
path: P,
|
||||
contract_name: &str,
|
||||
opt: bool,
|
||||
) -> Result<Self, Error> {
|
||||
// Load source file
|
||||
let mut src_file = File::open(path)
|
||||
.map_err(|_| Box::new(EvmTestError("src file open failed".to_string())))?;
|
||||
let mut src = String::new();
|
||||
src_file
|
||||
.read_to_string(&mut src)
|
||||
.map_err(|_| Box::new(EvmTestError("src file read failed".to_string())))?;
|
||||
|
||||
Self::compile_from_src_string(&src, contract_name, opt, &[])
|
||||
}
|
||||
|
||||
pub fn compile_from_src_string(
|
||||
src: &str,
|
||||
contract_name: &str,
|
||||
opt: bool,
|
||||
libraries: &[(&str, Token)],
|
||||
) -> Result<Self, Error> {
|
||||
// Compile source file using solc
|
||||
// Configuration: https://docs.soliditylang.org/en/v0.8.10/using-the-compiler.html
|
||||
// TODO: Change output selection to only compile 'input' file
|
||||
let solc_config = format!(
|
||||
r#"
|
||||
{{
|
||||
"language": "Solidity",
|
||||
"sources": {{ "input.sol": {{ "content": {} }} }},
|
||||
"settings": {{
|
||||
"optimizer": {{ "enabled": {} }},
|
||||
"libraries": {{
|
||||
"input.sol" : {{ {} }}
|
||||
}},
|
||||
"outputSelection": {{
|
||||
"*": {{
|
||||
"*": [
|
||||
"evm.bytecode.object", "abi"
|
||||
],
|
||||
"": [ "*" ] }}
|
||||
}}
|
||||
}}
|
||||
}}"#,
|
||||
json!(src),
|
||||
opt,
|
||||
libraries
|
||||
.iter()
|
||||
.map(|(name, address)| format!("\"{}\": \"0x{}\"", name, address))
|
||||
.collect::<Vec<_>>()
|
||||
.join(",\n")
|
||||
);
|
||||
|
||||
Self::compile_from_config(&solc_config, contract_name)
|
||||
}
|
||||
|
||||
pub fn compile_from_config(config: &str, contract_name: &str) -> Result<Self, Error> {
|
||||
// Compile source file using solc
|
||||
// Configuration: https://docs.soliditylang.org/en/v0.8.10/using-the-compiler.html
|
||||
let out = from_str::<serde_json::Value>(&compile(config))
|
||||
.map_err(|_| Box::new(EvmTestError("solc compile failed".to_string())))?;
|
||||
|
||||
if out["errors"].is_array()
|
||||
&& out["errors"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|e| e["severity"] == "error")
|
||||
{
|
||||
return Err(Box::new(EvmTestError(format!(
|
||||
"solc compiled with errors: {}",
|
||||
out["errors"]
|
||||
))));
|
||||
}
|
||||
|
||||
let binary = {
|
||||
let hex_code = out["contracts"]["input.sol"][contract_name]["evm"]["bytecode"]
|
||||
["object"]
|
||||
.to_string()
|
||||
.replace('\"', "");
|
||||
|
||||
hex::decode(&hex_code)
|
||||
.map_err(|_| Box::new(EvmTestError("decode hex binary failed".to_string())))?
|
||||
};
|
||||
let abi = {
|
||||
if out["contracts"]["input.sol"][contract_name]["abi"] == "null" {
|
||||
return Err(Box::new(EvmTestError(
|
||||
"solc compiled with null abi".to_string(),
|
||||
)));
|
||||
}
|
||||
ContractAbi::load(
|
||||
out["contracts"]["input.sol"][contract_name]["abi"]
|
||||
.to_string()
|
||||
.as_bytes(),
|
||||
)
|
||||
.map_err(|_| Box::new(EvmTestError("ethabi failed loading abi".to_string())))?
|
||||
};
|
||||
|
||||
Ok(Contract { binary, abi })
|
||||
}
|
||||
|
||||
pub fn encode_create_contract_bytes(&self, init: &[Token]) -> Result<Vec<u8>, Error> {
|
||||
match &self.abi.constructor {
|
||||
Some(constructor) => {
|
||||
let binary = constructor
|
||||
.encode_input(self.binary.clone(), init)
|
||||
.map_err(|_| {
|
||||
Box::new(EvmTestError(
|
||||
"abi constructor failed to encode inputs".to_string(),
|
||||
))
|
||||
})?;
|
||||
Ok(binary.to_vec())
|
||||
}
|
||||
None => Ok(self.binary.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn encode_call_contract_bytes(
|
||||
&self,
|
||||
fn_name: &str,
|
||||
input: &[Token],
|
||||
) -> Result<Vec<u8>, Error> {
|
||||
match self.abi.functions.get(fn_name) {
|
||||
Some(f) => {
|
||||
let call_binary = f[0].encode_input(input).map_err(|_| {
|
||||
Box::new(EvmTestError(
|
||||
"abi function failed to encode inputs".to_string(),
|
||||
))
|
||||
})?;
|
||||
Ok(call_binary.to_vec())
|
||||
}
|
||||
None => Err(Box::new(EvmTestError(
|
||||
"abi does not include function".to_string(),
|
||||
))),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
use primitive_types::U256;
|
||||
pub use revm::Return;
|
||||
use revm::{AccountInfo, Database, InMemoryDB, Log, TransactOut, TransactTo, EVM};
|
||||
|
||||
use crate::{address::Address, Error, EvmTestError};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CallResult {
|
||||
pub op_out: Return,
|
||||
pub out: Vec<u8>,
|
||||
pub gas: u64,
|
||||
pub log_out: Vec<Log>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CreateContractResult {
|
||||
pub addr: Address,
|
||||
pub gas: u64,
|
||||
}
|
||||
|
||||
pub struct Evm {
|
||||
vm: EVM<InMemoryDB>,
|
||||
}
|
||||
|
||||
impl Default for Evm {
|
||||
fn default() -> Self {
|
||||
let mut vm = revm::new();
|
||||
vm.database(InMemoryDB::default());
|
||||
Self { vm }
|
||||
}
|
||||
}
|
||||
|
||||
impl Evm {
|
||||
pub fn call(
|
||||
&mut self,
|
||||
input: Vec<u8>,
|
||||
addr: &Address,
|
||||
caller: &Address,
|
||||
) -> Result<CallResult, Error> {
|
||||
self.vm.env.tx.caller = *caller.as_ref();
|
||||
self.vm.env.tx.transact_to = TransactTo::Call(*addr.as_ref());
|
||||
self.vm.env.tx.data = input.into();
|
||||
let (op_out, tx_out, gas, log_out) = self.vm.transact_commit();
|
||||
let out = match tx_out {
|
||||
TransactOut::Call(out) => Ok(out.to_vec()),
|
||||
_ => Err(Box::new(EvmTestError(
|
||||
"call contract function failed".to_string(),
|
||||
))),
|
||||
}?;
|
||||
Ok(CallResult {
|
||||
op_out,
|
||||
out,
|
||||
gas,
|
||||
log_out,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn deploy(
|
||||
&mut self,
|
||||
contract: Vec<u8>,
|
||||
deployer: &Address,
|
||||
) -> Result<CreateContractResult, Error> {
|
||||
self.vm.env.tx.caller = *deployer.as_ref();
|
||||
self.vm.env.tx.transact_to = TransactTo::create();
|
||||
self.vm.env.tx.data = contract.into();
|
||||
let (_, tx_out, gas, _) = self.vm.transact_commit();
|
||||
let contract_address = match tx_out {
|
||||
TransactOut::Create(_, Some(addr)) => Ok(Address(addr)),
|
||||
_ => Err(Box::new(EvmTestError("create contract failed".to_string()))),
|
||||
}?;
|
||||
Ok(CreateContractResult {
|
||||
addr: contract_address,
|
||||
gas,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create_account(&mut self, address: &Address, balance: impl Into<U256>) {
|
||||
let acc = AccountInfo::from_balance(balance.into());
|
||||
self.vm.db().unwrap().insert_cache(*address.as_ref(), acc);
|
||||
}
|
||||
|
||||
pub fn set_account_balance(
|
||||
&mut self,
|
||||
address: &Address,
|
||||
balance: impl Into<U256>,
|
||||
) -> Result<(), Error> {
|
||||
let mut acc = self.vm.db().unwrap().basic(*address.as_ref());
|
||||
acc.balance = balance.into();
|
||||
self.vm.db().unwrap().insert_cache(*address.as_ref(), acc);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn balance_of(&mut self, address: &Address) -> U256 {
|
||||
self.vm.db().unwrap().basic(*address.as_ref()).balance
|
||||
}
|
||||
|
||||
pub fn get_account(&mut self, address: &Address) -> AccountInfo {
|
||||
self.vm.db().unwrap().basic(*address.as_ref())
|
||||
}
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
use primitive_types::U256;
|
||||
|
||||
use std::{
|
||||
error::Error as ErrorTrait,
|
||||
fmt::{self, Debug},
|
||||
};
|
||||
|
||||
pub mod address;
|
||||
pub mod contract;
|
||||
pub mod evm;
|
||||
|
||||
pub type Error = Box<dyn ErrorTrait>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EvmTestError(String);
|
||||
|
||||
impl ErrorTrait for EvmTestError {
|
||||
fn source(&self) -> Option<&(dyn ErrorTrait + 'static)> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for EvmTestError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_be_bytes(n: &U256) -> [u8; 32] {
|
||||
let mut input_bytes: [u8; 32] = [0; 32];
|
||||
n.to_big_endian(&mut input_bytes);
|
||||
input_bytes
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{address::Address, contract::Contract, evm::Evm};
|
||||
use ethabi::Token;
|
||||
use rand::{rngs::StdRng, SeedableRng};
|
||||
|
||||
#[test]
|
||||
fn simple_storage_contract_test() {
|
||||
let mut rng = StdRng::seed_from_u64(0u64);
|
||||
|
||||
// Compile contract
|
||||
let contract_path = format!(
|
||||
"{}/contracts/simple_storage.sol",
|
||||
env!("CARGO_MANIFEST_DIR")
|
||||
);
|
||||
let contract =
|
||||
Contract::compile_from_solidity_file(contract_path, "SimpleStorage", false).unwrap();
|
||||
|
||||
// Setup EVM
|
||||
let mut evm = Evm::default();
|
||||
let deployer = Address::random(&mut rng);
|
||||
evm.create_account(&deployer, 0);
|
||||
|
||||
// Deploy contract
|
||||
let create_result = evm
|
||||
.deploy(
|
||||
contract.encode_create_contract_bytes(&[]).unwrap(),
|
||||
&deployer,
|
||||
)
|
||||
.unwrap();
|
||||
let contract_addr = create_result.addr.clone();
|
||||
println!("Contract deploy gas cost: {}", create_result.gas);
|
||||
|
||||
// Call get function on contract
|
||||
let get_result = evm
|
||||
.call(
|
||||
contract.encode_call_contract_bytes("get", &[]).unwrap(),
|
||||
&contract_addr,
|
||||
&deployer,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(&get_result.out, &to_be_bytes(&U256::from(0)));
|
||||
|
||||
// Call set function on contract
|
||||
let _ = evm
|
||||
.call(
|
||||
contract
|
||||
.encode_call_contract_bytes(
|
||||
"set",
|
||||
&[Token::Tuple(vec![Token::Uint(U256::from(40))])],
|
||||
)
|
||||
.unwrap(),
|
||||
&contract_addr,
|
||||
&deployer,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Call get function on contract
|
||||
let get_result = evm
|
||||
.call(
|
||||
contract.encode_call_contract_bytes("get", &[]).unwrap(),
|
||||
&contract_addr,
|
||||
&deployer,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(&get_result.out, &to_be_bytes(&U256::from(40)));
|
||||
println!("{:?}", get_result);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_test"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
authors = ["schaeff <thibaut@schaeff.fr>"]
|
||||
edition = "2018"
|
||||
|
||||
|
@ -21,6 +21,7 @@ typed-arena = "1.4.1"
|
|||
wasm-bindgen-test = "^0.3.0"
|
||||
zokrates_ark = { version = "0.1", path = "../zokrates_ark" }
|
||||
zokrates_proof_systems = { version = "0.1", path = "../zokrates_proof_systems" }
|
||||
|
||||
rand_0_8 = { version = "0.8", package = "rand" }
|
||||
getrandom = { version = "0.2.8", features = ["js"] }
|
||||
|
||||
[lib]
|
||||
|
|
|
@ -10,6 +10,7 @@ use zokrates_field::Bn128Field;
|
|||
use zokrates_interpreter::Interpreter;
|
||||
use zokrates_proof_systems::{Backend, NonUniversalBackend};
|
||||
|
||||
use rand_0_8::{rngs::StdRng, SeedableRng};
|
||||
use zokrates_ark::Ark;
|
||||
use zokrates_proof_systems::groth16::G16;
|
||||
|
||||
|
@ -26,6 +27,8 @@ fn generate_proof() {
|
|||
.execute(program.clone(), &[Bn128Field::from(42)])
|
||||
.unwrap();
|
||||
|
||||
let keypair = <Ark as NonUniversalBackend<Bn128Field, G16>>::setup(program.clone());
|
||||
let _proof = <Ark as Backend<Bn128Field, G16>>::generate_proof(program, witness, keypair.pk);
|
||||
let rng = &mut StdRng::from_entropy();
|
||||
let keypair = <Ark as NonUniversalBackend<Bn128Field, G16>>::setup(program.clone(), rng);
|
||||
let _proof =
|
||||
<Ark as Backend<Bn128Field, G16>>::generate_proof(program, witness, keypair.pk, rng);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue