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

Merge branch 'develop' into ark-parallel

This commit is contained in:
dark64 2023-01-30 16:09:25 +01:00
commit a76e14c00b
41 changed files with 8834 additions and 594 deletions

View file

@ -119,11 +119,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"

14
Cargo.lock generated
View file

@ -1325,9 +1325,9 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.7"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
dependencies = [
"cfg-if 1.0.0",
"js-sys",
@ -3180,6 +3180,7 @@ dependencies = [
"pairing_ce",
"phase2",
"rand 0.4.6",
"rand 0.8.5",
"zokrates_ast",
"zokrates_field",
"zokrates_interpreter",
@ -3364,10 +3365,12 @@ name = "zokrates_js"
version = "1.1.4"
dependencies = [
"console_error_panic_hook",
"getrandom",
"indexmap",
"js-sys",
"json",
"lazy_static",
"rand 0.8.5",
"serde",
"serde_json",
"toml",
@ -3412,12 +3415,13 @@ dependencies = [
name = "zokrates_proof_systems"
version = "0.1.0"
dependencies = [
"blake2 0.8.1",
"byteorder",
"cfg-if 0.1.10",
"ethabi",
"getrandom",
"hex 0.4.3",
"primitive-types",
"rand 0.4.6",
"rand 0.8.5",
"regex 0.2.11",
"serde",
"zokrates_ast",
@ -3451,6 +3455,8 @@ dependencies = [
name = "zokrates_test"
version = "0.2.0"
dependencies = [
"getrandom",
"rand 0.8.5",
"serde",
"serde_derive",
"serde_json",

View file

@ -0,0 +1 @@
Allow user-provided randomness in setup and proof generation

View file

@ -0,0 +1 @@
Optimize `zokrates-js` library size

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -16,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]

View file

@ -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(&params);
let proof = computation.prove(&params, 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);

View file

@ -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(&params);
let rng = &mut StdRng::from_entropy();
let params = computation.clone().setup(rng);
let _proof = computation.prove(&params, rng);
}
#[test]
@ -278,8 +286,9 @@ mod tests {
let computation = Computation::with_witness(program, witness);
let params = computation.clone().setup();
let _proof = computation.prove(&params);
let rng = &mut StdRng::from_entropy();
let params = computation.clone().setup(rng);
let _proof = computation.prove(&params, rng);
}
#[test]
@ -298,8 +307,9 @@ mod tests {
let computation = Computation::with_witness(program, witness);
let params = computation.clone().setup();
let _proof = computation.prove(&params);
let rng = &mut StdRng::from_entropy();
let params = computation.clone().setup(rng);
let _proof = computation.prove(&params, 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(&params);
let rng = &mut StdRng::from_entropy();
let params = computation.clone().setup(rng);
let _proof = computation.prove(&params, 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(&params);
let rng = &mut StdRng::from_entropy();
let params = computation.clone().setup(rng);
let _proof = computation.prove(&params, rng);
}
#[test]
@ -371,8 +383,9 @@ mod tests {
let computation = Computation::with_witness(program, witness);
let params = computation.clone().setup();
let _proof = computation.prove(&params);
let rng = &mut StdRng::from_entropy();
let params = computation.clone().setup(rng);
let _proof = computation.prove(&params, 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(&params);
let rng = &mut StdRng::from_entropy();
let params = computation.clone().setup(rng);
let _proof = computation.prove(&params, rng);
}
}
}

View file

@ -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.

View file

@ -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`

View file

@ -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

View file

@ -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 =

View file

@ -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());

View file

@ -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");

View file

@ -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)

View file

@ -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)

View file

@ -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"] }

View file

@ -3,6 +3,6 @@ dist
target
pkg
wasm-pack.log
stdlib
stdlib.js
metadata.js
metadata.js
wasm.js
umd.min.js

View file

@ -15,6 +15,8 @@ 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_embed = { path = "../zokrates_embed", default-features = false }

View file

@ -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();
}

View 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";

View file

@ -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;

View file

@ -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 };

View file

@ -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" }),
};
};

View file

@ -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 };

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@
"name": "zokrates-js",
"version": "1.1.4",
"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",
"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
View 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);
})();

View file

@ -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

View file

@ -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())
}
@ -516,7 +528,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(
@ -537,25 +549,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")),
}
@ -588,27 +623,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)),
}
}
@ -617,6 +665,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();
@ -639,10 +688,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",
@ -650,35 +704,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")),

View file

@ -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;
@ -65,7 +65,7 @@ describe("tests", () => {
it("should resolve stdlib module", () => {
assert.doesNotThrow(() => {
const code = `import "utils/pack/bool/unpack" as unpack;\ndef main() { return; }`;
const code = `import "utils/pack/bool/unpack" as unpack;\ndef main() {}`;
zokratesProvider.compile(code);
});
});
@ -169,7 +169,7 @@ 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};
bool check = if (a == 0) { true } else { a * a == b };
assert(check);
return true;
}`;
@ -193,9 +193,33 @@ describe("tests", () => {
assert.doesNotThrow(() => {
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", () => {
assert.doesNotThrow(() => {
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);
}
});
});
@ -236,6 +260,37 @@ describe("tests", () => {
);
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", () => {
assert.doesNotThrow(() => {
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);
});
});
@ -364,8 +419,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)))

View 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>

View 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();
});
});

View file

@ -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"

View file

@ -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,

View 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)
}

View file

@ -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]

View file

@ -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);
}