fix conflicts
This commit is contained in:
parent
80f4aa4939
commit
8f5e4d9985
47 changed files with 1707 additions and 498 deletions
|
@ -84,6 +84,7 @@ jobs:
|
|||
deploy:
|
||||
docker:
|
||||
- image: cimg/python:3.8-node
|
||||
resource_class: large
|
||||
steps:
|
||||
- checkout
|
||||
- setup_remote_docker:
|
||||
|
|
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -14,6 +14,13 @@ proof.json
|
|||
universal_setup.dat
|
||||
witness
|
||||
|
||||
# ZoKrates source files at the root of the repository
|
||||
/*.zok
|
||||
|
||||
# snarkjs artifacts
|
||||
*.wtns
|
||||
*.r1cs
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
|
||||
# Cargo.lock
|
||||
|
|
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.
|
|||
## [Unreleased]
|
||||
https://github.com/Zokrates/ZoKrates/compare/latest...develop
|
||||
|
||||
## [0.7.14] - 2022-05-31
|
||||
|
||||
### Release
|
||||
- https://github.com/Zokrates/ZoKrates/releases/tag/0.7.14 <!-- markdown-link-check-disable-line -->
|
||||
|
||||
### Changes
|
||||
- Add curve and scheme to the verification key and proof, detect these parameters on `verify`, `print-proof`, and `export-verifier` (#1152, @schaeff)
|
||||
- Fix `one_liner.sh` script not resolving latest github tag (#1146, @dark64)
|
||||
- Fix instructions to build from source (#1141, @schaeff)
|
||||
- Fix keccak padding issue, allow arbitrary input size (#1139, @dark64)
|
||||
- Fix tuple assignment when rhs is a conditional (#1138, @dark64)
|
||||
|
||||
## [0.7.13] - 2022-04-18
|
||||
|
||||
### Release
|
||||
|
|
540
Cargo.lock
generated
540
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -18,6 +18,7 @@ members = [
|
|||
"zokrates_bellman",
|
||||
"zokrates_proof_systems",
|
||||
"zokrates_js",
|
||||
"zokrates_circom"
|
||||
]
|
||||
|
||||
exclude = []
|
|
@ -26,7 +26,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain none -y \
|
||||
&& rustup toolchain install $RUST_VERSION --allow-downgrade --profile minimal --component rustfmt clippy \
|
||||
&& curl -sL https://deb.nodesource.com/setup_14.x | bash - && apt-get install -y nodejs && npm i -g solc \
|
||||
&& curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs && npm i -g solc \
|
||||
&& curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh \
|
||||
&& curl -sL https://raw.githubusercontent.com/Sarcasm/run-clang-format/master/run-clang-format.py > /opt/run-clang-format.py \
|
||||
&& chmod +x /opt/run-clang-format.py \
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Fix tuple assignment when rhs is a conditional
|
|
@ -1 +0,0 @@
|
|||
Fix keccak padding issue, allow arbitrary input size
|
|
@ -1 +0,0 @@
|
|||
Fix instructions to build from source
|
1
changelogs/unreleased/1143-schaeff
Normal file
1
changelogs/unreleased/1143-schaeff
Normal file
|
@ -0,0 +1 @@
|
|||
Optionally export snarkjs artifacts
|
|
@ -1 +0,0 @@
|
|||
Fix `one_liner.sh` script not resolving latest github tag
|
|
@ -1 +0,0 @@
|
|||
Add curve and scheme to the verification key and proof, detect these parameters on `verify`, `print-proof`, and `export-verifier`
|
1
changelogs/unreleased/1169-dark64
Normal file
1
changelogs/unreleased/1169-dark64
Normal file
|
@ -0,0 +1 @@
|
|||
Fix constant inlining for tuples
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
apt-get update -y
|
||||
apt-get install -y curl gnupg sudo build-essential git
|
||||
curl -sL https://deb.nodesource.com/setup_12.x | bash -
|
||||
curl -sL https://deb.nodesource.com/setup_16.x | bash -
|
||||
apt-get install -y nodejs
|
||||
npm i -g solc
|
|
@ -72,15 +72,15 @@ fn ark_combination<T: Field + ArkFieldExtensions>(
|
|||
.fold(LinearCombination::zero(), |acc, e| acc + e)
|
||||
}
|
||||
|
||||
impl<T: Field + ArkFieldExtensions, I: IntoIterator<Item = Statement<T>>> Computation<T, I> {
|
||||
pub fn public_inputs_values(&self) -> Vec<<T::ArkEngine as PairingEngine>::Fr> {
|
||||
self.program
|
||||
.public_inputs(self.witness.as_ref().unwrap())
|
||||
.iter()
|
||||
.map(|v| v.clone().into_ark())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
// impl<T: Field + ArkFieldExtensions, I: IntoIterator<Item = Statement<T>>> Computation<T, I> {
|
||||
// pub fn public_inputs_values(&self) -> Vec<<T::ArkEngine as PairingEngine>::Fr> {
|
||||
// self.program
|
||||
// .public_inputs(self.witness.as_ref().unwrap())
|
||||
// .iter()
|
||||
// .map(|v| v.clone().into_ark())
|
||||
// .collect()
|
||||
// }
|
||||
// }
|
||||
|
||||
impl<T: Field + ArkFieldExtensions, I: IntoIterator<Item = Statement<T>>>
|
||||
ConstraintSynthesizer<<<T as ArkFieldExtensions>::ArkEngine as PairingEngine>::Fr>
|
||||
|
@ -153,6 +153,28 @@ impl<T: Field + ArkFieldExtensions, I: IntoIterator<Item = Statement<T>>>
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field + ArkFieldExtensions, I: IntoIterator<Item = Statement<T>>> Computation<T, I> {
|
||||
pub fn public_inputs_values(&self) -> Vec<<T::ArkEngine as PairingEngine>::Fr> {
|
||||
self.program
|
||||
.public_inputs_values(self.witness.as_ref().unwrap())
|
||||
.iter()
|
||||
.map(|v| v.clone().into_ark())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
// impl<T: Field + ArkFieldExtensions, I: IntoIterator<Item = Statement<T>>>
|
||||
// ConstraintSynthesizer<<<T as ArkFieldExtensions>::ArkEngine as PairingEngine>::Fr>
|
||||
// for Computation<T, I>
|
||||
// {
|
||||
// fn generate_constraints(
|
||||
// self,
|
||||
// cs: ConstraintSystemRef<<<T as ArkFieldExtensions>::ArkEngine as PairingEngine>::Fr>,
|
||||
// ) -> Result<(), SynthesisError> {
|
||||
// self.program.generate_constraints(cs, self.witness)
|
||||
// }
|
||||
// }
|
||||
|
||||
mod parse {
|
||||
use super::*;
|
||||
use ark_ff::ToBytes;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::common::{Parameter, RuntimeError, Solver, Variable};
|
||||
use crate::flat::{flat_expression_from_bits, flat_expression_from_variable_summands};
|
||||
use crate::flat::{FlatDirective, FlatExpression, FlatFunctionIterator, FlatStatement};
|
||||
use crate::typed::types::{
|
||||
ConcreteGenericsAssignment, DeclarationConstant, DeclarationSignature, DeclarationType,
|
||||
|
@ -308,29 +309,6 @@ impl FlatEmbed {
|
|||
}
|
||||
}
|
||||
|
||||
// util to convert a vector of `(variable_id, coefficient)` to a flat_expression
|
||||
// we build a binary tree of additions by splitting the vector recursively
|
||||
#[cfg(any(feature = "ark", feature = "bellman"))]
|
||||
fn flat_expression_from_vec<T: Field>(v: &[(usize, T)]) -> FlatExpression<T> {
|
||||
match v.len() {
|
||||
0 => FlatExpression::Number(T::zero()),
|
||||
1 => {
|
||||
let (key, val) = v[0].clone();
|
||||
FlatExpression::Mult(
|
||||
box FlatExpression::Number(val),
|
||||
box FlatExpression::Identifier(Variable::new(key)),
|
||||
)
|
||||
}
|
||||
n => {
|
||||
let (u, v) = v.split_at(n / 2);
|
||||
FlatExpression::Add(
|
||||
box flat_expression_from_vec::<T>(u),
|
||||
box flat_expression_from_vec::<T>(v),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a flat function which computes a sha256 round
|
||||
///
|
||||
/// # Remarks
|
||||
|
@ -400,9 +378,9 @@ pub fn sha256_round<T: Field>(
|
|||
// insert flattened statements to represent constraints
|
||||
let constraint_statements = r1cs.constraints.into_iter().map(|c| {
|
||||
let c = from_bellman::<T, Bn256>(c);
|
||||
let rhs_a = flat_expression_from_vec::<T>(c.a.as_slice());
|
||||
let rhs_b = flat_expression_from_vec::<T>(c.b.as_slice());
|
||||
let lhs = flat_expression_from_vec::<T>(c.c.as_slice());
|
||||
let rhs_a = flat_expression_from_variable_summands::<T>(c.a.as_slice());
|
||||
let rhs_b = flat_expression_from_variable_summands::<T>(c.b.as_slice());
|
||||
let lhs = flat_expression_from_variable_summands::<T>(c.c.as_slice());
|
||||
|
||||
FlatStatement::Condition(
|
||||
lhs,
|
||||
|
@ -508,9 +486,9 @@ pub fn snark_verify_bls12_377<T: Field>(
|
|||
.into_iter()
|
||||
.map(|c| {
|
||||
let c = from_ark::<T, Bls12_377>(c);
|
||||
let rhs_a = flat_expression_from_vec::<T>(c.a.as_slice());
|
||||
let rhs_b = flat_expression_from_vec::<T>(c.b.as_slice());
|
||||
let lhs = flat_expression_from_vec::<T>(c.c.as_slice());
|
||||
let rhs_a = flat_expression_from_variable_summands::<T>(c.a.as_slice());
|
||||
let rhs_b = flat_expression_from_variable_summands::<T>(c.b.as_slice());
|
||||
let lhs = flat_expression_from_variable_summands::<T>(c.c.as_slice());
|
||||
|
||||
FlatStatement::Condition(
|
||||
lhs,
|
||||
|
@ -614,17 +592,11 @@ pub fn unpack_to_bitwidth<T: Field>(
|
|||
.collect();
|
||||
|
||||
// sum check: o253 + o252 * 2 + ... + o{253 - (bit_width - 1)} * 2**(bit_width - 1)
|
||||
let mut lhs_sum = FlatExpression::Number(T::from(0));
|
||||
|
||||
for i in 0..bit_width {
|
||||
lhs_sum = FlatExpression::Add(
|
||||
box lhs_sum,
|
||||
box FlatExpression::Mult(
|
||||
box FlatExpression::Identifier(Variable::new(bit_width - i)),
|
||||
box FlatExpression::Number(T::from(2).pow(i)),
|
||||
),
|
||||
);
|
||||
}
|
||||
let lhs_sum = flat_expression_from_bits(
|
||||
(0..bit_width)
|
||||
.map(|i| FlatExpression::Identifier(Variable::new(i + 1)))
|
||||
.collect(),
|
||||
);
|
||||
|
||||
statements.push(FlatStatement::Condition(
|
||||
lhs_sum,
|
||||
|
|
|
@ -8,7 +8,7 @@ use std::fmt;
|
|||
// id < 0 for public outputs
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Hash, Eq, Ord, PartialOrd, Copy)]
|
||||
pub struct Variable {
|
||||
id: isize,
|
||||
pub id: isize,
|
||||
}
|
||||
|
||||
impl Variable {
|
||||
|
|
|
@ -6,11 +6,17 @@
|
|||
//! @date 2017
|
||||
|
||||
pub mod folder;
|
||||
pub mod utils;
|
||||
|
||||
pub use crate::common::Parameter;
|
||||
pub use crate::common::RuntimeError;
|
||||
pub use crate::common::Variable;
|
||||
|
||||
pub use utils::{
|
||||
flat_expression_from_bits, flat_expression_from_expression_summands,
|
||||
flat_expression_from_variable_summands,
|
||||
};
|
||||
|
||||
use crate::common::Solver;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
|
|
53
zokrates_ast/src/flat/utils.rs
Normal file
53
zokrates_ast/src/flat/utils.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
use crate::flat::{FlatExpression, Variable};
|
||||
use zokrates_field::Field;
|
||||
|
||||
// util to convert a vector of `(coefficient, expression)` to a flat_expression
|
||||
// we build a binary tree of additions by splitting the vector recursively
|
||||
pub fn flat_expression_from_expression_summands<T: Field, U: Clone + Into<FlatExpression<T>>>(
|
||||
v: &[(T, U)],
|
||||
) -> FlatExpression<T> {
|
||||
match v.len() {
|
||||
0 => FlatExpression::Number(T::zero()),
|
||||
1 => {
|
||||
let (val, var) = v[0].clone();
|
||||
FlatExpression::Mult(box FlatExpression::Number(val), box var.into())
|
||||
}
|
||||
n => {
|
||||
let (u, v) = v.split_at(n / 2);
|
||||
FlatExpression::Add(
|
||||
box flat_expression_from_expression_summands(u),
|
||||
box flat_expression_from_expression_summands(v),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flat_expression_from_bits<T: Field>(v: Vec<FlatExpression<T>>) -> FlatExpression<T> {
|
||||
flat_expression_from_expression_summands(
|
||||
&v.into_iter()
|
||||
.rev()
|
||||
.enumerate()
|
||||
.map(|(index, var)| (T::from(2).pow(index), var))
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn flat_expression_from_variable_summands<T: Field>(v: &[(T, usize)]) -> FlatExpression<T> {
|
||||
match v.len() {
|
||||
0 => FlatExpression::Number(T::zero()),
|
||||
1 => {
|
||||
let (val, var) = v[0].clone();
|
||||
FlatExpression::Mult(
|
||||
box FlatExpression::Number(val),
|
||||
box FlatExpression::Identifier(Variable::new(var)),
|
||||
)
|
||||
}
|
||||
n => {
|
||||
let (u, v) = v.split_at(n / 2);
|
||||
FlatExpression::Add(
|
||||
box flat_expression_from_variable_summands(u),
|
||||
box flat_expression_from_variable_summands(v),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
//use crate::solvers::Solver;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeSet;
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
use zokrates_field::Field;
|
||||
|
@ -29,6 +30,8 @@ pub enum Statement<T> {
|
|||
Directive(Directive<T>),
|
||||
}
|
||||
|
||||
pub type PublicInputs = BTreeSet<Variable>;
|
||||
|
||||
impl<T: Field> Statement<T> {
|
||||
pub fn definition<U: Into<QuadComb<T>>>(v: Variable, e: U) -> Self {
|
||||
Statement::Constraint(e.into(), v.into(), None)
|
||||
|
@ -108,10 +111,18 @@ impl<T, I: IntoIterator<Item = Statement<T>>> ProgIterator<T, I> {
|
|||
pub fn public_count(&self) -> usize {
|
||||
self.arguments.iter().filter(|a| !a.private).count() + self.return_count
|
||||
}
|
||||
|
||||
pub fn public_inputs(&self) -> PublicInputs {
|
||||
self.arguments
|
||||
.iter()
|
||||
.filter(|a| !a.private)
|
||||
.map(|a| a.id)
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field, I: IntoIterator<Item = Statement<T>>> ProgIterator<T, I> {
|
||||
pub fn public_inputs(&self, witness: &Witness<T>) -> Vec<T> {
|
||||
pub fn public_inputs_values(&self, witness: &Witness<T>) -> Vec<T> {
|
||||
self.arguments
|
||||
.iter()
|
||||
.filter(|p| !p.private)
|
||||
|
|
|
@ -20,11 +20,11 @@ impl<T: Field> fmt::Display for SMTLib2Display<'_, T> {
|
|||
}
|
||||
}
|
||||
|
||||
struct FlatVariableCollector {
|
||||
struct VariableCollector {
|
||||
variables: BTreeSet<Variable>,
|
||||
}
|
||||
|
||||
impl<T: Field> Visitor<T> for FlatVariableCollector {
|
||||
impl<T: Field> Visitor<T> for VariableCollector {
|
||||
fn visit_variable(&mut self, v: &Variable) {
|
||||
self.variables.insert(*v);
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ impl<T: Field> Visitor<T> for FlatVariableCollector {
|
|||
|
||||
impl<T: Field> SMTLib2 for Prog<T> {
|
||||
fn to_smtlib2(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut collector = FlatVariableCollector {
|
||||
let mut collector = VariableCollector {
|
||||
variables: BTreeSet::<Variable>::new(),
|
||||
};
|
||||
collector.visit_module(self);
|
||||
|
|
|
@ -180,7 +180,7 @@ impl<T: BellmanFieldExtensions + Field, I: IntoIterator<Item = Statement<T>>> Co
|
|||
|
||||
pub fn public_inputs_values(&self) -> Vec<<T::BellmanEngine as ScalarEngine>::Fr> {
|
||||
self.program
|
||||
.public_inputs(self.witness.as_ref().unwrap())
|
||||
.public_inputs_values(self.witness.as_ref().unwrap())
|
||||
.iter()
|
||||
.map(|v| v.clone().into_bellman())
|
||||
.collect()
|
||||
|
|
17
zokrates_circom/Cargo.toml
Normal file
17
zokrates_circom/Cargo.toml
Normal file
|
@ -0,0 +1,17 @@
|
|||
[package]
|
||||
name = "zokrates_circom"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
zokrates_core = { version = "0.6", path = "../zokrates_core", default-features = false }
|
||||
zokrates_ast = { version = "0.1", path = "../zokrates_ast", default-features = false }
|
||||
zokrates_field = { version = "0.5.0", path = "../zokrates_field", default-features = false }
|
||||
byteorder = "1.4.3"
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "1.2.1"
|
||||
zkutil = "0.5.0"
|
||||
bellman_ce = { version = "^0.3" }
|
90
zokrates_circom/src/lib.rs
Normal file
90
zokrates_circom/src/lib.rs
Normal file
|
@ -0,0 +1,90 @@
|
|||
mod r1cs;
|
||||
mod witness;
|
||||
|
||||
pub use r1cs::write_r1cs;
|
||||
pub use witness::write_witness;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::io::Cursor;
|
||||
|
||||
use bellman_ce::pairing::bn256::Bn256;
|
||||
use zkutil::circom_circuit::{
|
||||
create_rng, generate_random_parameters, prove, r1cs_from_bin, witness_from_bin,
|
||||
CircomCircuit,
|
||||
};
|
||||
use zokrates_ast::{
|
||||
flat::{Parameter, Variable},
|
||||
ir::{LinComb, Prog, PublicInputs, QuadComb, Statement, Witness},
|
||||
};
|
||||
use zokrates_field::Bn128Field;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn setup_and_prove() {
|
||||
let prog: Prog<Bn128Field> = Prog {
|
||||
arguments: vec![
|
||||
Parameter::private(Variable::new(0)),
|
||||
Parameter::public(Variable::new(1)),
|
||||
],
|
||||
return_count: 1,
|
||||
statements: vec![
|
||||
Statement::Constraint(
|
||||
QuadComb::from_linear_combinations(
|
||||
LinComb::from(Variable::new(0)),
|
||||
LinComb::from(Variable::new(0)),
|
||||
),
|
||||
LinComb::from(Variable::new(0)),
|
||||
None,
|
||||
),
|
||||
Statement::Constraint(
|
||||
(LinComb::from(Variable::new(0)) + LinComb::from(Variable::new(1))).into(),
|
||||
Variable::public(0).into(),
|
||||
None,
|
||||
),
|
||||
],
|
||||
};
|
||||
|
||||
let mut r1cs = vec![];
|
||||
|
||||
write_r1cs(&mut r1cs, prog).unwrap();
|
||||
|
||||
let public_inputs: PublicInputs = vec![Variable::new(1)].into_iter().collect();
|
||||
|
||||
let witness: Witness<Bn128Field> = Witness(
|
||||
vec![
|
||||
(Variable::new(0), Bn128Field::from(1u32)),
|
||||
(Variable::new(1), Bn128Field::from(1u32)),
|
||||
(Variable::one(), Bn128Field::from(1u32)),
|
||||
(Variable::public(0), Bn128Field::from(2u32)),
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
);
|
||||
|
||||
let mut wtns = vec![];
|
||||
|
||||
write_witness(&mut wtns, witness, public_inputs).unwrap();
|
||||
|
||||
let (r1cs, mapping) = r1cs_from_bin(Cursor::new(r1cs)).unwrap();
|
||||
let wtns = witness_from_bin::<Bn256, _>(Cursor::new(wtns)).unwrap();
|
||||
|
||||
let rng = create_rng();
|
||||
let circuit = CircomCircuit {
|
||||
r1cs: r1cs.clone(),
|
||||
witness: None,
|
||||
wire_mapping: None,
|
||||
};
|
||||
|
||||
let params = generate_random_parameters(circuit, rng).unwrap();
|
||||
|
||||
let circuit = CircomCircuit {
|
||||
r1cs,
|
||||
witness: Some(wtns),
|
||||
wire_mapping: Some(mapping),
|
||||
};
|
||||
let rng = create_rng();
|
||||
assert!(prove(circuit.clone(), ¶ms, rng).is_ok());
|
||||
}
|
||||
}
|
416
zokrates_circom/src/r1cs.rs
Normal file
416
zokrates_circom/src/r1cs.rs
Normal file
|
@ -0,0 +1,416 @@
|
|||
use byteorder::{LittleEndian, WriteBytesExt};
|
||||
use std::collections::HashMap;
|
||||
use std::io::Result;
|
||||
use std::{io::Write, ops::Add};
|
||||
use zokrates_ast::flat::Variable;
|
||||
use zokrates_ast::ir::{Prog, Statement};
|
||||
use zokrates_field::Field;
|
||||
struct Header {
|
||||
pub field_size: u32,
|
||||
pub prime_size: Vec<u8>,
|
||||
pub n_wires: u32,
|
||||
pub n_pub_out: u32,
|
||||
pub n_pub_in: u32,
|
||||
pub n_prv_in: u32,
|
||||
pub n_labels: u64,
|
||||
pub n_constraints: u32,
|
||||
}
|
||||
|
||||
type LinComb<T> = Vec<(usize, T)>;
|
||||
type Constraint<T> = (LinComb<T>, LinComb<T>, LinComb<T>);
|
||||
|
||||
fn write_header<W: Write>(writer: &mut W, header: Header) -> Result<()> {
|
||||
writer.write_u32::<LittleEndian>(header.field_size)?;
|
||||
writer.write_all(&header.prime_size)?;
|
||||
writer.write_u32::<LittleEndian>(header.n_wires)?;
|
||||
writer.write_u32::<LittleEndian>(header.n_pub_out)?;
|
||||
writer.write_u32::<LittleEndian>(header.n_pub_in)?;
|
||||
writer.write_u32::<LittleEndian>(header.n_prv_in)?;
|
||||
writer.write_u64::<LittleEndian>(header.n_labels)?;
|
||||
writer.write_u32::<LittleEndian>(header.n_constraints)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the index of `var` in `variables`, adding `var` with incremented index if it does not yet exists.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `variables` - A mutual map that maps all existing variables to their index.
|
||||
/// * `var` - Variable to be searched for.
|
||||
pub fn provide_variable_idx(variables: &mut HashMap<Variable, usize>, var: &Variable) -> usize {
|
||||
let index = variables.len();
|
||||
*variables.entry(*var).or_insert(index)
|
||||
}
|
||||
|
||||
/// Calculates one R1CS row representation of a program and returns (V, A, B, C) so that:
|
||||
/// * `V` contains all used variables and the index in the vector represents the used number in `A`, `B`, `C`
|
||||
/// * `<A,x>*<B,x> = <C,x>` for a witness `x`
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `prog` - The program the representation is calculated for.
|
||||
pub fn r1cs_program<T: Field>(prog: Prog<T>) -> (Vec<Variable>, usize, Vec<Constraint<T>>) {
|
||||
let mut variables: HashMap<Variable, usize> = HashMap::new();
|
||||
provide_variable_idx(&mut variables, &Variable::one());
|
||||
|
||||
for i in 0..prog.return_count {
|
||||
provide_variable_idx(&mut variables, &Variable::public(i));
|
||||
}
|
||||
|
||||
for x in prog.arguments.iter().filter(|p| !p.private) {
|
||||
provide_variable_idx(&mut variables, &x.id);
|
||||
}
|
||||
|
||||
// position where private part of witness starts
|
||||
let private_inputs_offset = variables.len();
|
||||
|
||||
// first pass through statements to populate `variables`
|
||||
for (quad, lin) in prog.statements.iter().filter_map(|s| match s {
|
||||
Statement::Constraint(quad, lin, _) => Some((quad, lin)),
|
||||
Statement::Directive(..) => None,
|
||||
}) {
|
||||
for (k, _) in &quad.left.0 {
|
||||
provide_variable_idx(&mut variables, k);
|
||||
}
|
||||
for (k, _) in &quad.right.0 {
|
||||
provide_variable_idx(&mut variables, k);
|
||||
}
|
||||
for (k, _) in &lin.0 {
|
||||
provide_variable_idx(&mut variables, k);
|
||||
}
|
||||
}
|
||||
|
||||
let mut constraints = vec![];
|
||||
|
||||
// second pass to convert program to raw sparse vectors
|
||||
for (quad, lin) in prog.statements.into_iter().filter_map(|s| match s {
|
||||
Statement::Constraint(quad, lin, _) => Some((quad, lin)),
|
||||
Statement::Directive(..) => None,
|
||||
}) {
|
||||
constraints.push((
|
||||
quad.left
|
||||
.0
|
||||
.into_iter()
|
||||
.map(|(k, v)| (*variables.get(&k).unwrap(), v))
|
||||
.collect(),
|
||||
quad.right
|
||||
.0
|
||||
.into_iter()
|
||||
.map(|(k, v)| (*variables.get(&k).unwrap(), v))
|
||||
.collect(),
|
||||
lin.0
|
||||
.into_iter()
|
||||
.map(|(k, v)| (*variables.get(&k).unwrap(), v))
|
||||
.collect(),
|
||||
));
|
||||
}
|
||||
|
||||
// Convert map back into list ordered by index
|
||||
let mut variables_list = vec![Variable::new(0); variables.len()];
|
||||
for (k, v) in variables.drain() {
|
||||
assert_eq!(variables_list[v], Variable::new(0));
|
||||
variables_list[v] = k;
|
||||
}
|
||||
(variables_list, private_inputs_offset, constraints)
|
||||
}
|
||||
|
||||
pub fn write_r1cs<T: Field, W: Write>(writer: &mut W, p: Prog<T>) -> Result<()> {
|
||||
let modulo_byte_count = T::max_value().to_biguint().add(1u32).to_bytes_le().len() as u32;
|
||||
|
||||
let n_pub_out = p.return_count as u32;
|
||||
let n_pub_in = p.arguments.iter().filter(|a| !a.private).count() as u32;
|
||||
let n_prv_in = p.arguments.iter().filter(|a| a.private).count() as u32;
|
||||
|
||||
let (vars, _, constraints) = r1cs_program(p);
|
||||
|
||||
let n_wires = vars.len();
|
||||
|
||||
let header = Header {
|
||||
field_size: modulo_byte_count,
|
||||
prime_size: T::max_value().to_biguint().add(1u32).to_bytes_le(),
|
||||
n_wires: n_wires as u32,
|
||||
n_pub_out,
|
||||
n_pub_in,
|
||||
n_prv_in,
|
||||
n_labels: n_wires as u64,
|
||||
n_constraints: constraints.len() as u32,
|
||||
};
|
||||
|
||||
// magic
|
||||
writer.write_all(&[0x72, 0x31, 0x63, 0x73])?;
|
||||
// version
|
||||
writer.write_u32::<LittleEndian>(1)?;
|
||||
// section count
|
||||
writer.write_u32::<LittleEndian>(3)?;
|
||||
|
||||
// section type: constraints
|
||||
// type
|
||||
writer.write_u32::<LittleEndian>(2)?;
|
||||
// size: 4 per lc + (32 + 4) per summand
|
||||
let size = constraints
|
||||
.iter()
|
||||
.map(|(a, b, c)| {
|
||||
(3 * 4 // for each lc, 4 bytes for its size
|
||||
+ (a.len() + b.len() + c.len()) // for each summand
|
||||
* (modulo_byte_count as usize + 4)) // 4 bytes for the signal, `modulo_byte_count` bytes for the coefficient
|
||||
as u64
|
||||
})
|
||||
.sum();
|
||||
writer.write_u64::<LittleEndian>(size)?;
|
||||
|
||||
write_constraints(writer, constraints)?;
|
||||
|
||||
// section type: header
|
||||
// type
|
||||
writer.write_u32::<LittleEndian>(1)?;
|
||||
// size
|
||||
writer.write_u64::<LittleEndian>(32 + 32)?;
|
||||
|
||||
// header
|
||||
write_header(writer, header)?;
|
||||
|
||||
// section type: wire2label
|
||||
// type
|
||||
writer.write_u32::<LittleEndian>(3)?;
|
||||
// size
|
||||
writer.write_u64::<LittleEndian>(n_wires as u64 * 8)?;
|
||||
|
||||
write_table(writer, &vars)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_constraints<T: Field, W: Write>(
|
||||
writer: &mut W,
|
||||
constraints: Vec<Constraint<T>>,
|
||||
) -> Result<()> {
|
||||
for c in constraints {
|
||||
write_lincomb(writer, c.0)?;
|
||||
write_lincomb(writer, c.1)?;
|
||||
write_lincomb(writer, c.2)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_lincomb<T: Field, W: Write>(writer: &mut W, l: LinComb<T>) -> Result<()> {
|
||||
writer.write_u32::<LittleEndian>(l.len() as u32)?;
|
||||
for (var, coeff) in l {
|
||||
writer.write_u32::<LittleEndian>(var as u32)?;
|
||||
let mut res = vec![0u8; 32];
|
||||
for (value, padded) in coeff.to_biguint().to_bytes_le().iter().zip(res.iter_mut()) {
|
||||
*padded = *value;
|
||||
}
|
||||
writer.write_all(&res)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// for now we do not write any signal map
|
||||
fn write_table<W: Write>(w: &mut W, variables: &[Variable]) -> Result<()> {
|
||||
for (i, _) in variables.iter().enumerate() {
|
||||
w.write_u64::<LittleEndian>(i as u64)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::io::Cursor;
|
||||
|
||||
use super::*;
|
||||
use pretty_assertions::assert_eq;
|
||||
use zkutil::r1cs_reader;
|
||||
use zokrates_ast::{
|
||||
flat::{Parameter, Variable},
|
||||
ir::{LinComb, QuadComb, Statement},
|
||||
};
|
||||
use zokrates_field::Bn128Field;
|
||||
|
||||
#[test]
|
||||
fn empty() {
|
||||
let prog: Prog<Bn128Field> = Prog::default();
|
||||
let mut buf = Vec::new();
|
||||
|
||||
#[rustfmt::skip]
|
||||
let expected: Vec<u8> = vec![
|
||||
// magic
|
||||
0x72, 0x31, 0x63, 0x73,
|
||||
// version
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
// section count
|
||||
0x03, 0x00, 0x00, 0x00,
|
||||
// constraints section (empty)
|
||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// header
|
||||
0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// modulus size in bytes
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
// modulus
|
||||
0x01, 0x00, 0x00, 0xf0, 0x93, 0xf5, 0xe1, 0x43, 0x91, 0x70, 0xb9, 0x79, 0x48, 0xe8, 0x33, 0x28, 0x5d, 0x58, 0x81, 0x81, 0xb6, 0x45, 0x50, 0xb8, 0x29, 0xa0, 0x31, 0xe1, 0x72, 0x4e, 0x64, 0x30,
|
||||
// n wires
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
// n pub outputs
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
// n pub inputs
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
// n priv
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
// n labels
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// n constraints
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
// wire map (variable one?)
|
||||
0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
];
|
||||
|
||||
write_r1cs(&mut buf, prog).unwrap();
|
||||
|
||||
assert_eq!(buf, expected);
|
||||
|
||||
let c = Cursor::new(buf);
|
||||
|
||||
assert!(r1cs_reader::read(c).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn return_one() {
|
||||
let prog: Prog<Bn128Field> = Prog {
|
||||
arguments: vec![],
|
||||
return_count: 1,
|
||||
statements: vec![Statement::Constraint(
|
||||
LinComb::one().into(),
|
||||
Variable::public(0).into(),
|
||||
None,
|
||||
)],
|
||||
};
|
||||
|
||||
let mut buf = Vec::new();
|
||||
|
||||
#[rustfmt::skip]
|
||||
let expected: Vec<u8> = vec![
|
||||
0x72, 0x31, 0x63, 0x73,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // size = 1 constraint = sum(4 /* write term_count_i */ + term_count_i * (4 + 32)) = 120
|
||||
0x01, 0x00, 0x00, 0x00, // 1 element in this lc
|
||||
0x00, 0x00, 0x00, 0x00, // variable 0
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // coeff 1
|
||||
0x01, 0x00, 0x00, 0x00, // 1 element in this lc
|
||||
0x00, 0x00, 0x00, 0x00, // variable 0
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // coeff 1
|
||||
0x01, 0x00, 0x00, 0x00, // 1 element in this lc
|
||||
0x01, 0x00, 0x00, 0x00, // variable 1
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // coeff 1
|
||||
// header
|
||||
0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// modulo size
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
// modulo
|
||||
0x01, 0x00, 0x00, 0xf0, 0x93, 0xf5, 0xe1, 0x43, 0x91, 0x70, 0xb9, 0x79, 0x48, 0xe8, 0x33, 0x28, 0x5d, 0x58, 0x81, 0x81, 0xb6, 0x45, 0x50, 0xb8, 0x29, 0xa0, 0x31, 0xe1, 0x72, 0x4e, 0x64, 0x30,
|
||||
0x02, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
// wire map (one, pub0)
|
||||
0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
];
|
||||
|
||||
write_r1cs(&mut buf, prog).unwrap();
|
||||
|
||||
assert_eq!(buf, expected);
|
||||
|
||||
let c = Cursor::new(buf);
|
||||
|
||||
assert!(r1cs_reader::read(c).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_inputs() {
|
||||
let prog: Prog<Bn128Field> = Prog {
|
||||
arguments: vec![
|
||||
Parameter::private(Variable::new(0)),
|
||||
Parameter::public(Variable::new(1)),
|
||||
],
|
||||
return_count: 1,
|
||||
statements: vec![
|
||||
Statement::Constraint(
|
||||
QuadComb::from_linear_combinations(
|
||||
LinComb::from(Variable::new(0)),
|
||||
LinComb::from(Variable::new(0)),
|
||||
),
|
||||
LinComb::from(Variable::new(0)),
|
||||
None,
|
||||
),
|
||||
Statement::Constraint(
|
||||
(LinComb::from(Variable::new(0)) + LinComb::from(Variable::new(1))).into(),
|
||||
Variable::public(0).into(),
|
||||
None,
|
||||
),
|
||||
],
|
||||
};
|
||||
|
||||
let mut buf = Vec::new();
|
||||
|
||||
#[rustfmt::skip]
|
||||
let expected: Vec<u8> = vec![
|
||||
0x72, 0x31, 0x63, 0x73,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// first constraint
|
||||
0x01, 0x00, 0x00, 0x00, // 1 element in this lc
|
||||
0x03, 0x00, 0x00, 0x00, // variable 3
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // coeff 1
|
||||
0x01, 0x00, 0x00, 0x00, // 1 element in this lc
|
||||
0x03, 0x00, 0x00, 0x00, // variable 3
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // coeff 1
|
||||
0x01, 0x00, 0x00, 0x00, // 1 element in this lc
|
||||
0x03, 0x00, 0x00, 0x00, // variable 3
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // coeff 1
|
||||
// second constraint
|
||||
0x01, 0x00, 0x00, 0x00, // 1 element in this lc
|
||||
0x00, 0x00, 0x00, 0x00, // variable 0
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // coeff 1
|
||||
0x02, 0x00, 0x00, 0x00, // 2 element in this lc
|
||||
0x03, 0x00, 0x00, 0x00, // variable 3
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // coeff 1
|
||||
0x02, 0x00, 0x00, 0x00, // variable 2
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // coeff 1
|
||||
0x01, 0x00, 0x00, 0x00, // 1 element in this lc
|
||||
0x01, 0x00, 0x00, 0x00, // variable 1
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // coeff 1
|
||||
// header
|
||||
0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// modulo size
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
// modulo
|
||||
0x01, 0x00, 0x00, 0xf0, 0x93, 0xf5, 0xe1, 0x43, 0x91, 0x70, 0xb9, 0x79, 0x48, 0xe8, 0x33, 0x28, 0x5d, 0x58, 0x81, 0x81, 0xb6, 0x45, 0x50, 0xb8, 0x29, 0xa0, 0x31, 0xe1, 0x72, 0x4e, 0x64, 0x30,
|
||||
0x04, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00,
|
||||
// wire map (one, ~out_0, _1, _0)
|
||||
0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
];
|
||||
|
||||
write_r1cs(&mut buf, prog).unwrap();
|
||||
|
||||
assert_eq!(buf, expected);
|
||||
|
||||
let c = Cursor::new(buf);
|
||||
|
||||
assert!(r1cs_reader::read(c).is_ok());
|
||||
}
|
||||
}
|
219
zokrates_circom/src/witness.rs
Normal file
219
zokrates_circom/src/witness.rs
Normal file
|
@ -0,0 +1,219 @@
|
|||
use std::{
|
||||
io::{Result, Write},
|
||||
ops::Add,
|
||||
};
|
||||
|
||||
use byteorder::{LittleEndian, WriteBytesExt};
|
||||
use zokrates_ast::{
|
||||
flat::Variable,
|
||||
ir::{PublicInputs, Witness},
|
||||
};
|
||||
use zokrates_field::Field;
|
||||
|
||||
pub struct Header {
|
||||
pub field_size: u32,
|
||||
pub prime_size: Vec<u8>,
|
||||
pub witness_size: u32,
|
||||
}
|
||||
|
||||
fn write_header<W: Write>(writer: &mut W, header: Header) -> Result<()> {
|
||||
writer.write_u32::<LittleEndian>(header.field_size)?;
|
||||
writer.write_all(&header.prime_size)?;
|
||||
writer.write_u32::<LittleEndian>(header.witness_size)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_witness<T: Field, W: Write>(
|
||||
writer: &mut W,
|
||||
w: Witness<T>,
|
||||
public_inputs: PublicInputs,
|
||||
) -> Result<()> {
|
||||
let modulo_byte_count = T::max_value().to_biguint().add(1u32).to_bytes_le().len() as u32;
|
||||
let witness_size = w.0.len() as u32;
|
||||
|
||||
let header = Header {
|
||||
field_size: modulo_byte_count,
|
||||
prime_size: T::max_value().to_biguint().add(1u32).to_bytes_le(),
|
||||
witness_size,
|
||||
};
|
||||
|
||||
// magic "wtns"
|
||||
writer.write_all(&[0x77, 0x74, 0x6e, 0x73])?;
|
||||
// version
|
||||
writer.write_u32::<LittleEndian>(2)?;
|
||||
// section count
|
||||
writer.write_u32::<LittleEndian>(2)?;
|
||||
|
||||
// section type: header
|
||||
// type
|
||||
writer.write_u32::<LittleEndian>(1)?;
|
||||
// size
|
||||
writer.write_u64::<LittleEndian>(8 + modulo_byte_count as u64)?;
|
||||
|
||||
// header
|
||||
write_header(writer, header)?;
|
||||
|
||||
// section type: witness
|
||||
// type
|
||||
writer.write_u32::<LittleEndian>(2)?;
|
||||
// size: `modulo_byte_count` per witness value
|
||||
let size = witness_size as u64 * modulo_byte_count as u64;
|
||||
writer.write_u64::<LittleEndian>(size)?;
|
||||
|
||||
write_witness_values(writer, w, public_inputs)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_val<T: Field, W: Write>(writer: &mut W, v: &T, modulo_byte_count: usize) -> Result<()> {
|
||||
let mut res = vec![0u8; modulo_byte_count];
|
||||
for (value, padded) in v.to_biguint().to_bytes_le().iter().zip(res.iter_mut()) {
|
||||
*padded = *value;
|
||||
}
|
||||
writer.write_all(&res)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_witness_values<T: Field, W: Write>(
|
||||
writer: &mut W,
|
||||
mut w: Witness<T>,
|
||||
public_inputs: PublicInputs,
|
||||
) -> Result<()> {
|
||||
let modulo_byte_count = T::max_value().to_biguint().add(1u32).to_bytes_le().len();
|
||||
|
||||
if let Some(value) = w.0.remove(&Variable::one()) {
|
||||
write_val(writer, &value, modulo_byte_count)?;
|
||||
}
|
||||
|
||||
let output_count = w.0.iter().filter(|(var, _)| var.is_output()).count();
|
||||
|
||||
for value in (0..output_count).map(|id| w.0.remove(&Variable::public(id)).unwrap()) {
|
||||
write_val(writer, &value, modulo_byte_count)?;
|
||||
}
|
||||
|
||||
for value in public_inputs.iter().map(|var| w.0.remove(var).unwrap()) {
|
||||
write_val(writer, &value, modulo_byte_count)?;
|
||||
}
|
||||
|
||||
for (_, val) in w.0.iter() {
|
||||
write_val(writer, val, modulo_byte_count)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use pretty_assertions::assert_eq;
|
||||
use zokrates_ast::{flat::Variable, ir::PublicInputs};
|
||||
use zokrates_field::Bn128Field;
|
||||
|
||||
#[test]
|
||||
fn empty() {
|
||||
let w: Witness<Bn128Field> = Witness::default();
|
||||
let public_inputs: PublicInputs = Default::default();
|
||||
let mut buf = Vec::new();
|
||||
|
||||
#[rustfmt::skip]
|
||||
let expected: Vec<u8> = vec![
|
||||
// magic
|
||||
0x77, 0x74, 0x6e, 0x73,
|
||||
// version
|
||||
0x02, 0x00, 0x00, 0x00,
|
||||
// section count
|
||||
0x02, 0x00, 0x00, 0x00,
|
||||
// header
|
||||
0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// modulus size in bytes
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
// modulus
|
||||
0x01, 0x00, 0x00, 0xf0, 0x93, 0xf5, 0xe1, 0x43, 0x91, 0x70, 0xb9, 0x79, 0x48, 0xe8, 0x33, 0x28, 0x5d, 0x58, 0x81, 0x81, 0xb6, 0x45, 0x50, 0xb8, 0x29, 0xa0, 0x31, 0xe1, 0x72, 0x4e, 0x64, 0x30,
|
||||
// witness size
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
// witness section (empty)
|
||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
];
|
||||
|
||||
write_witness(&mut buf, w, public_inputs).unwrap();
|
||||
|
||||
assert_eq!(buf, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_value() {
|
||||
let mut w: Witness<Bn128Field> = Witness::default();
|
||||
let public_inputs: PublicInputs = Default::default();
|
||||
w.0.insert(Variable::public(0), 1.into());
|
||||
let mut buf = Vec::new();
|
||||
|
||||
#[rustfmt::skip]
|
||||
let expected: Vec<u8> = vec![
|
||||
// magic
|
||||
0x77, 0x74, 0x6e, 0x73,
|
||||
// version
|
||||
0x02, 0x00, 0x00, 0x00,
|
||||
// section count
|
||||
0x02, 0x00, 0x00, 0x00,
|
||||
// header
|
||||
0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// modulus size in bytes
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
// modulus
|
||||
0x01, 0x00, 0x00, 0xf0, 0x93, 0xf5, 0xe1, 0x43, 0x91, 0x70, 0xb9, 0x79, 0x48, 0xe8, 0x33, 0x28, 0x5d, 0x58, 0x81, 0x81, 0xb6, 0x45, 0x50, 0xb8, 0x29, 0xa0, 0x31, 0xe1, 0x72, 0x4e, 0x64, 0x30,
|
||||
// witness size
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
// witness section
|
||||
0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// values
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
];
|
||||
|
||||
write_witness(&mut buf, w, public_inputs).unwrap();
|
||||
|
||||
assert_eq!(buf, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_and_pub_and_priv() {
|
||||
let mut w: Witness<Bn128Field> = Witness::default();
|
||||
let public_inputs: PublicInputs = vec![Variable::new(1)].into_iter().collect();
|
||||
w.0.extend(vec![
|
||||
(Variable::public(0), 42.into()),
|
||||
(Variable::one(), 1.into()),
|
||||
(Variable::new(0), 43.into()),
|
||||
(Variable::new(1), 44.into()),
|
||||
]);
|
||||
let mut buf = Vec::new();
|
||||
|
||||
#[rustfmt::skip]
|
||||
let expected: Vec<u8> = vec![
|
||||
// magic
|
||||
0x77, 0x74, 0x6e, 0x73,
|
||||
// version
|
||||
0x02, 0x00, 0x00, 0x00,
|
||||
// section count
|
||||
0x02, 0x00, 0x00, 0x00,
|
||||
// header
|
||||
0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// modulus size in bytes
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
// modulus
|
||||
0x01, 0x00, 0x00, 0xf0, 0x93, 0xf5, 0xe1, 0x43, 0x91, 0x70, 0xb9, 0x79, 0x48, 0xe8, 0x33, 0x28, 0x5d, 0x58, 0x81, 0x81, 0xb6, 0x45, 0x50, 0xb8, 0x29, 0xa0, 0x31, 0xe1, 0x72, 0x4e, 0x64, 0x30,
|
||||
// witness size
|
||||
0x04, 0x00, 0x00, 0x00,
|
||||
// witness section
|
||||
0x02, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// values: ordering should be [one, ~out_0, _1, _0] because _1 is public
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
];
|
||||
|
||||
write_witness(&mut buf, w, public_inputs).unwrap();
|
||||
|
||||
assert_eq!(buf, expected);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_cli"
|
||||
version = "0.7.13"
|
||||
version = "0.7.14"
|
||||
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"
|
||||
|
@ -22,6 +22,7 @@ zokrates_abi = { version = "0.1", path = "../zokrates_abi" }
|
|||
zokrates_core = { version = "0.6", 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 }
|
||||
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 }
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use zokrates_common::constants::*;
|
||||
|
||||
pub const FLATTENED_CODE_DEFAULT_PATH: &str = "out";
|
||||
pub const CIRCOM_R1CS_DEFAULT_PATH: &str = "out.r1cs";
|
||||
pub const CIRCOM_WITNESS_DEFAULT_PATH: &str = "out.wtns";
|
||||
pub const ABI_SPEC_DEFAULT_PATH: &str = "abi.json";
|
||||
pub const VERIFICATION_KEY_DEFAULT_PATH: &str = "verification.key";
|
||||
pub const PROVING_KEY_DEFAULT_PATH: &str = "proving.key";
|
||||
|
|
|
@ -6,6 +6,7 @@ use std::fs::File;
|
|||
use std::io::{BufReader, BufWriter, Read};
|
||||
use std::path::{Path, PathBuf};
|
||||
use typed_arena::Arena;
|
||||
use zokrates_circom::write_r1cs;
|
||||
use zokrates_common::constants::BN128;
|
||||
use zokrates_common::helpers::CurveParameter;
|
||||
use zokrates_core::compile::{compile, CompileConfig, CompileError};
|
||||
|
@ -46,7 +47,15 @@ pub fn subcommand() -> App<'static, 'static> {
|
|||
.takes_value(true)
|
||||
.required(false)
|
||||
.default_value(cli_constants::FLATTENED_CODE_DEFAULT_PATH)
|
||||
).arg(Arg::with_name("curve")
|
||||
).arg(Arg::with_name("r1cs")
|
||||
.short("r1cs")
|
||||
.long("r1cs")
|
||||
.help("Path of the output r1cs file")
|
||||
.value_name("FILE")
|
||||
.takes_value(true)
|
||||
.required(false)
|
||||
.default_value(cli_constants::CIRCOM_R1CS_DEFAULT_PATH)
|
||||
).arg(Arg::with_name("curve")
|
||||
.short("c")
|
||||
.long("curve")
|
||||
.help("Curve to be used in the compilation")
|
||||
|
@ -75,6 +84,7 @@ fn cli_compile<T: Field>(sub_matches: &ArgMatches) -> Result<(), String> {
|
|||
println!("Compiling {}\n", sub_matches.value_of("input").unwrap());
|
||||
let path = PathBuf::from(sub_matches.value_of("input").unwrap());
|
||||
let bin_output_path = Path::new(sub_matches.value_of("output").unwrap());
|
||||
let r1cs_output_path = Path::new(sub_matches.value_of("r1cs").unwrap());
|
||||
let abi_spec_path = Path::new(sub_matches.value_of("abi-spec").unwrap());
|
||||
|
||||
log::debug!("Load entry point file {}", path.display());
|
||||
|
@ -133,9 +143,17 @@ fn cli_compile<T: Field>(sub_matches: &ArgMatches) -> Result<(), String> {
|
|||
let bin_output_file = File::create(&bin_output_path)
|
||||
.map_err(|why| format!("Could not create {}: {}", bin_output_path.display(), why))?;
|
||||
|
||||
let mut writer = BufWriter::new(bin_output_file);
|
||||
let r1cs_output_file = File::create(&r1cs_output_path)
|
||||
.map_err(|why| format!("Could not create {}: {}", r1cs_output_path.display(), why))?;
|
||||
|
||||
match program_flattened.serialize(&mut writer) {
|
||||
let mut bin_writer = BufWriter::new(bin_output_file);
|
||||
let mut r1cs_writer = BufWriter::new(r1cs_output_file);
|
||||
|
||||
let program_flattened = program_flattened.collect();
|
||||
|
||||
write_r1cs(&mut r1cs_writer, program_flattened.clone()).unwrap();
|
||||
|
||||
match program_flattened.serialize(&mut bin_writer) {
|
||||
Ok(constraint_count) => {
|
||||
// serialize ABI spec and write to JSON file
|
||||
log::debug!("Serialize ABI");
|
||||
|
|
|
@ -10,6 +10,7 @@ use zokrates_ast::typed::{
|
|||
abi::Abi,
|
||||
types::{ConcreteSignature, ConcreteType, GTupleType},
|
||||
};
|
||||
use zokrates_circom::write_witness;
|
||||
use zokrates_field::Field;
|
||||
|
||||
pub fn subcommand() -> App<'static, 'static> {
|
||||
|
@ -34,11 +35,18 @@ pub fn subcommand() -> App<'static, 'static> {
|
|||
).arg(Arg::with_name("output")
|
||||
.short("o")
|
||||
.long("output")
|
||||
.help("Path of the output file")
|
||||
.help("Path of the output witness file")
|
||||
.value_name("FILE")
|
||||
.takes_value(true)
|
||||
.required(false)
|
||||
.default_value(cli_constants::WITNESS_DEFAULT_PATH)
|
||||
).arg(Arg::with_name("circom-witness")
|
||||
.long("circom-witness")
|
||||
.help("Path of the output circom witness file")
|
||||
.value_name("FILE")
|
||||
.takes_value(true)
|
||||
.required(false)
|
||||
.default_value(cli_constants::CIRCOM_WITNESS_DEFAULT_PATH)
|
||||
).arg(Arg::with_name("arguments")
|
||||
.short("a")
|
||||
.long("arguments")
|
||||
|
@ -161,6 +169,8 @@ fn cli_compute<T: Field, I: Iterator<Item = ir::Statement<T>>>(
|
|||
|
||||
let interpreter = zokrates_interpreter::Interpreter::default();
|
||||
|
||||
let public_inputs = ir_prog.public_inputs();
|
||||
|
||||
let witness = interpreter
|
||||
.execute(ir_prog, &arguments.encode())
|
||||
.map_err(|e| format!("Execution failed: {}", e))?;
|
||||
|
@ -185,6 +195,16 @@ fn cli_compute<T: Field, I: Iterator<Item = ir::Statement<T>>>(
|
|||
.write(writer)
|
||||
.map_err(|why| format!("Could not save witness: {:?}", why))?;
|
||||
|
||||
// write circom witness to file
|
||||
let wtns_path = Path::new(sub_matches.value_of("circom-witness").unwrap());
|
||||
let wtns_file = File::create(&wtns_path)
|
||||
.map_err(|why| format!("Could not create {}: {}", output_path.display(), why))?;
|
||||
|
||||
let mut writer = BufWriter::new(wtns_file);
|
||||
|
||||
write_witness(&mut writer, witness, public_inputs)
|
||||
.map_err(|why| format!("Could not save circom witness: {:?}", why))?;
|
||||
|
||||
println!("Witness file written to '{}'", output_path.display());
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_common"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
authors = ["dark64 <darem966@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_core"
|
||||
version = "0.6.12"
|
||||
version = "0.6.13"
|
||||
edition = "2018"
|
||||
authors = ["Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>", "Dennis Kuhnert <mail@kyroy.com>"]
|
||||
repository = "https://github.com/Zokrates/ZoKrates"
|
||||
|
|
|
@ -33,6 +33,26 @@ impl<'a, 'ast, T: Field> ConstantsReader<'a, 'ast, T> {
|
|||
}
|
||||
|
||||
impl<'a, 'ast, T: Field> Folder<'ast, T> for ConstantsReader<'a, 'ast, T> {
|
||||
fn fold_declaration_constant(
|
||||
&mut self,
|
||||
c: DeclarationConstant<'ast, T>,
|
||||
) -> DeclarationConstant<'ast, T> {
|
||||
match c {
|
||||
DeclarationConstant::Constant(c) => {
|
||||
let c = self.fold_canonical_constant_identifier(c);
|
||||
|
||||
match self.constants.get(&c).cloned() {
|
||||
Some(e) => match UExpression::try_from(e).unwrap().into_inner() {
|
||||
UExpressionInner::Value(v) => DeclarationConstant::Concrete(v as u32),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
None => DeclarationConstant::Constant(c),
|
||||
}
|
||||
}
|
||||
c => fold_declaration_constant(self, c),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_field_expression(
|
||||
&mut self,
|
||||
e: FieldElementExpression<'ast, T>,
|
||||
|
@ -169,24 +189,4 @@ impl<'a, 'ast, T: Field> Folder<'ast, T> for ConstantsReader<'a, 'ast, T> {
|
|||
e => fold_struct_expression_inner(self, ty, e),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_declaration_constant(
|
||||
&mut self,
|
||||
c: DeclarationConstant<'ast, T>,
|
||||
) -> DeclarationConstant<'ast, T> {
|
||||
match c {
|
||||
DeclarationConstant::Constant(c) => {
|
||||
let c = self.fold_canonical_constant_identifier(c);
|
||||
|
||||
match self.constants.get(&c).cloned() {
|
||||
Some(e) => match UExpression::try_from(e).unwrap().into_inner() {
|
||||
UExpressionInner::Value(v) => DeclarationConstant::Concrete(v as u32),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
None => DeclarationConstant::Constant(c),
|
||||
}
|
||||
}
|
||||
c => fold_declaration_constant(self, c),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
16
zokrates_core_test/tests/tests/constants/tuple.json
Normal file
16
zokrates_core_test/tests/tests/constants/tuple.json
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/constants/tuple.zok",
|
||||
"max_constraint_count": 3,
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": []
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": [[["1", "1"], true]]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
5
zokrates_core_test/tests/tests/constants/tuple.zok
Normal file
5
zokrates_core_test/tests/tests/constants/tuple.zok
Normal file
|
@ -0,0 +1,5 @@
|
|||
const u32 N = 2
|
||||
const (field[N], bool) A = ([1; N], true)
|
||||
|
||||
def main() -> ((field[N], bool)):
|
||||
return A
|
|
@ -165,11 +165,7 @@ pub fn generate_verify_constraints(
|
|||
.into_iter()
|
||||
.zip(matrices.b.into_iter())
|
||||
.zip(matrices.c.into_iter())
|
||||
.map(|((a, b), c)| Constraint {
|
||||
a: a.into_iter().map(|(f, index)| (index, f)).collect(),
|
||||
b: b.into_iter().map(|(f, index)| (index, f)).collect(),
|
||||
c: c.into_iter().map(|(f, index)| (index, f)).collect(),
|
||||
})
|
||||
.map(|((a, b), c)| Constraint { a, b, c })
|
||||
.collect();
|
||||
|
||||
(
|
||||
|
@ -309,26 +305,26 @@ pub fn from_ark<T: zokrates_field::Field, E: PairingEngine>(c: Constraint<E::Fq>
|
|||
Constraint {
|
||||
a: c.a
|
||||
.into_iter()
|
||||
.map(|(index, fq)| {
|
||||
.map(|(fq, index)| {
|
||||
let mut res: Vec<u8> = vec![];
|
||||
fq.into_repr().write_le(&mut res).unwrap();
|
||||
(index, T::from_byte_vector(res))
|
||||
(T::from_byte_vector(res), index)
|
||||
})
|
||||
.collect(),
|
||||
b: c.b
|
||||
.into_iter()
|
||||
.map(|(index, fq)| {
|
||||
.map(|(fq, index)| {
|
||||
let mut res: Vec<u8> = vec![];
|
||||
fq.into_repr().write_le(&mut res).unwrap();
|
||||
(index, T::from_byte_vector(res))
|
||||
(T::from_byte_vector(res), index)
|
||||
})
|
||||
.collect(),
|
||||
c: c.c
|
||||
.into_iter()
|
||||
.map(|(index, fq)| {
|
||||
.map(|(fq, index)| {
|
||||
let mut res: Vec<u8> = vec![];
|
||||
fq.into_repr().write_le(&mut res).unwrap();
|
||||
(index, T::from_byte_vector(res))
|
||||
(T::from_byte_vector(res), index)
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
|
|
|
@ -180,17 +180,17 @@ impl<E: Engine> ConstraintSystem<E> for R1CS<E::Fr> {
|
|||
let a = a
|
||||
.as_ref()
|
||||
.iter()
|
||||
.map(|(variable, coefficient)| (var_to_index(*variable), *coefficient))
|
||||
.map(|(variable, coefficient)| (*coefficient, var_to_index(*variable)))
|
||||
.collect();
|
||||
let b = b
|
||||
.as_ref()
|
||||
.iter()
|
||||
.map(|(variable, coefficient)| (var_to_index(*variable), *coefficient))
|
||||
.map(|(variable, coefficient)| (*coefficient, var_to_index(*variable)))
|
||||
.collect();
|
||||
let c = c
|
||||
.as_ref()
|
||||
.iter()
|
||||
.map(|(variable, coefficient)| (var_to_index(*variable), *coefficient))
|
||||
.map(|(variable, coefficient)| (*coefficient, var_to_index(*variable)))
|
||||
.collect();
|
||||
|
||||
self.constraints.push(Constraint { a, b, c });
|
||||
|
@ -257,26 +257,26 @@ pub fn from_bellman<T: zokrates_field::Field, E: Engine>(c: Constraint<E::Fr>) -
|
|||
Constraint {
|
||||
a: c.a
|
||||
.into_iter()
|
||||
.map(|(index, fq)| {
|
||||
.map(|(fq, index)| {
|
||||
let mut res: Vec<u8> = vec![];
|
||||
fq.into_repr().write_le(&mut res).unwrap();
|
||||
(index, T::from_byte_vector(res))
|
||||
(T::from_byte_vector(res), index)
|
||||
})
|
||||
.collect(),
|
||||
b: c.b
|
||||
.into_iter()
|
||||
.map(|(index, fq)| {
|
||||
.map(|(fq, index)| {
|
||||
let mut res: Vec<u8> = vec![];
|
||||
fq.into_repr().write_le(&mut res).unwrap();
|
||||
(index, T::from_byte_vector(res))
|
||||
(T::from_byte_vector(res), index)
|
||||
})
|
||||
.collect(),
|
||||
c: c.c
|
||||
.into_iter()
|
||||
.map(|(index, fq)| {
|
||||
.map(|(fq, index)| {
|
||||
let mut res: Vec<u8> = vec![];
|
||||
fq.into_repr().write_le(&mut res).unwrap();
|
||||
(index, T::from_byte_vector(res))
|
||||
(T::from_byte_vector(res), index)
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ pub struct Witness<T> {
|
|||
|
||||
#[derive(Default, Debug, PartialEq, Clone)]
|
||||
pub struct Constraint<T> {
|
||||
pub a: Vec<(usize, T)>,
|
||||
pub b: Vec<(usize, T)>,
|
||||
pub c: Vec<(usize, T)>,
|
||||
pub a: Vec<(T, usize)>,
|
||||
pub b: Vec<(T, usize)>,
|
||||
pub c: Vec<(T, usize)>,
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_js"
|
||||
version = "1.0.43"
|
||||
version = "1.0.44"
|
||||
authors = ["Darko Macesic"]
|
||||
edition = "2018"
|
||||
|
||||
|
@ -21,5 +21,6 @@ zokrates_ast = { path = "../zokrates_ast", default-features = false, features =
|
|||
zokrates_interpreter = { path = "../zokrates_interpreter", default-features = false, features = ["ark"] }
|
||||
zokrates_field = { path = "../zokrates_field", default-features = false }
|
||||
zokrates_abi = { path = "../zokrates_abi", default-features = false, features = ["ark"] }
|
||||
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
|
14
zokrates_js/index.d.ts
vendored
14
zokrates_js/index.d.ts
vendored
|
@ -19,6 +19,7 @@ declare module "zokrates-js" {
|
|||
location?: string;
|
||||
resolveCallback?: ResolveCallback;
|
||||
config?: CompileConfig;
|
||||
snarkjs?: boolean;
|
||||
}
|
||||
|
||||
export type Proof = {
|
||||
|
@ -31,9 +32,16 @@ declare module "zokrates-js" {
|
|||
location: string;
|
||||
}
|
||||
|
||||
export interface ComputeOptions {
|
||||
snarkjs?: boolean;
|
||||
}
|
||||
|
||||
export interface ComputationResult {
|
||||
witness: string;
|
||||
output: string;
|
||||
snarkjs?: {
|
||||
witness: Uint8Array;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Abi {
|
||||
|
@ -44,6 +52,9 @@ declare module "zokrates-js" {
|
|||
export interface CompilationArtifacts {
|
||||
program: Uint8Array;
|
||||
abi: Abi;
|
||||
snarkjs?: {
|
||||
program: Uint8Array;
|
||||
};
|
||||
}
|
||||
|
||||
export interface SetupKeypair {
|
||||
|
@ -64,7 +75,8 @@ declare module "zokrates-js" {
|
|||
): CompilationArtifacts;
|
||||
computeWitness(
|
||||
input: CompilationArtifacts | Uint8Array,
|
||||
args: any[]
|
||||
args: any[],
|
||||
options?: ComputeOptions
|
||||
): ComputationResult;
|
||||
setup(program: Uint8Array): SetupKeypair;
|
||||
universalSetup(size: number): Uint8Array;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "zokrates-js",
|
||||
"version": "1.0.43",
|
||||
"version": "1.0.44",
|
||||
"module": "index.js",
|
||||
"main": "node/index.js",
|
||||
"description": "JavaScript bindings for ZoKrates",
|
||||
|
@ -43,7 +43,7 @@
|
|||
"clean-node-pkg": "rimraf node/pkg/README.md node/pkg/.gitignore",
|
||||
"pretest": "npm run setup && npm run build:node:dev",
|
||||
"test": "npm run run-tests",
|
||||
"run-tests": "mocha --timeout 30000 --require esm --recursive tests"
|
||||
"run-tests": "mocha --timeout 100000 --require esm --recursive tests"
|
||||
},
|
||||
"devDependencies": {
|
||||
"dree": "^2.6.1",
|
||||
|
@ -53,6 +53,7 @@
|
|||
"mocha": "^9.2.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"serve": "^11.3.2",
|
||||
"snarkjs": "^0.4.19",
|
||||
"text-encoding": "^0.7.0",
|
||||
"toml": "^3.0.0",
|
||||
"wasm-pack": "^0.10.2"
|
||||
|
|
|
@ -11,6 +11,7 @@ use zokrates_ast::ir;
|
|||
use zokrates_ast::ir::ProgEnum;
|
||||
use zokrates_ast::typed::abi::Abi;
|
||||
use zokrates_ast::typed::types::{ConcreteSignature, ConcreteType, GTupleType};
|
||||
use zokrates_circom::{write_r1cs, write_witness};
|
||||
use zokrates_common::helpers::{CurveParameter, SchemeParameter};
|
||||
use zokrates_common::Resolver;
|
||||
use zokrates_core::compile::{
|
||||
|
@ -29,6 +30,7 @@ use zokrates_proof_systems::{
|
|||
pub struct CompilationResult {
|
||||
program: Vec<u8>,
|
||||
abi: Abi,
|
||||
snarkjs_program: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
|
@ -41,6 +43,14 @@ impl CompilationResult {
|
|||
pub fn abi(&self) -> JsValue {
|
||||
JsValue::from_serde(&self.abi).unwrap()
|
||||
}
|
||||
|
||||
pub fn snarkjs_program(&self) -> Option<js_sys::Uint8Array> {
|
||||
self.snarkjs_program.as_ref().map(|p| {
|
||||
let arr = js_sys::Uint8Array::new_with_length(p.len() as u32);
|
||||
arr.copy_from(p);
|
||||
arr
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
@ -49,10 +59,28 @@ pub struct ResolverResult {
|
|||
location: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[wasm_bindgen]
|
||||
pub struct ComputationResult {
|
||||
witness: String,
|
||||
output: String,
|
||||
snarkjs_witness: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl ComputationResult {
|
||||
pub fn witness(&self) -> JsValue {
|
||||
JsValue::from_str(&self.witness)
|
||||
}
|
||||
pub fn output(&self) -> JsValue {
|
||||
JsValue::from_str(&self.output)
|
||||
}
|
||||
pub fn snarkjs_witness(&self) -> Option<js_sys::Uint8Array> {
|
||||
self.snarkjs_witness.as_ref().map(|w| {
|
||||
let arr = js_sys::Uint8Array::new_with_length(w.len() as u32);
|
||||
arr.copy_from(w);
|
||||
arr
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct JsResolver<'a> {
|
||||
|
@ -107,7 +135,12 @@ mod internal {
|
|||
config: JsValue,
|
||||
) -> Result<CompilationResult, JsValue> {
|
||||
let resolver = JsResolver::new(resolve_callback);
|
||||
let config: CompileConfig = config.into_serde().unwrap_or_default();
|
||||
let config: serde_json::Value = config.into_serde().unwrap();
|
||||
let with_snarkjs_program = config
|
||||
.get("snarkjs")
|
||||
.map(|v| *v == serde_json::Value::Bool(true))
|
||||
.unwrap_or(false);
|
||||
let config: CompileConfig = serde_json::from_value(config).unwrap_or_default();
|
||||
|
||||
let fmt_error = |e: &CompileError| format!("{}:{}", e.file().display(), e.value());
|
||||
|
||||
|
@ -131,13 +164,19 @@ mod internal {
|
|||
|
||||
let abi = artifacts.abi().clone();
|
||||
|
||||
let program = artifacts.prog();
|
||||
let program = artifacts.prog().collect();
|
||||
let snarkjs_program = with_snarkjs_program.then(|| {
|
||||
let mut buffer = Cursor::new(vec![]);
|
||||
write_r1cs(&mut buffer, program.clone()).unwrap();
|
||||
buffer.into_inner()
|
||||
});
|
||||
let mut buffer = Cursor::new(vec![]);
|
||||
let _ = program.serialize(&mut buffer);
|
||||
|
||||
Ok(CompilationResult {
|
||||
abi,
|
||||
program: buffer.into_inner(),
|
||||
snarkjs_program,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -145,9 +184,16 @@ mod internal {
|
|||
program: ir::Prog<T>,
|
||||
abi: JsValue,
|
||||
args: JsValue,
|
||||
) -> Result<JsValue, JsValue> {
|
||||
config: JsValue,
|
||||
) -> Result<ComputationResult, JsValue> {
|
||||
let input = args.as_string().unwrap();
|
||||
|
||||
let config: serde_json::Value = config.into_serde().unwrap();
|
||||
let with_snarkjs_witness = config
|
||||
.get("snarkjs")
|
||||
.map(|v| *v == serde_json::Value::Bool(true))
|
||||
.unwrap_or(false);
|
||||
|
||||
let (inputs, signature) = if abi.is_object() {
|
||||
let abi: Abi = abi.into_serde().map_err(|err| {
|
||||
JsValue::from_str(&format!("Could not deserialize `abi`: {}", err))
|
||||
|
@ -175,6 +221,8 @@ mod internal {
|
|||
|
||||
let interpreter = zokrates_interpreter::Interpreter::default();
|
||||
|
||||
let public_inputs = program.public_inputs();
|
||||
|
||||
let witness = interpreter
|
||||
.execute(program, &inputs.encode())
|
||||
.map_err(|err| JsValue::from_str(&format!("Execution failed: {}", err)))?;
|
||||
|
@ -183,12 +231,17 @@ mod internal {
|
|||
zokrates_abi::Value::decode(witness.return_values(), *signature.output)
|
||||
.into_serde_json();
|
||||
|
||||
let result = ComputationResult {
|
||||
let snarkjs_witness = with_snarkjs_witness.then(|| {
|
||||
let mut buffer = Cursor::new(vec![]);
|
||||
write_witness(&mut buffer, witness.clone(), public_inputs).unwrap();
|
||||
buffer.into_inner()
|
||||
});
|
||||
|
||||
Ok(ComputationResult {
|
||||
witness: format!("{}", witness),
|
||||
output: to_string_pretty(&return_values).unwrap(),
|
||||
};
|
||||
|
||||
Ok(JsValue::from_serde(&result).unwrap())
|
||||
snarkjs_witness,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn setup_non_universal<
|
||||
|
@ -313,15 +366,20 @@ pub fn compile(
|
|||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn compute_witness(program: &[u8], abi: JsValue, args: JsValue) -> Result<JsValue, JsValue> {
|
||||
pub fn compute_witness(
|
||||
program: &[u8],
|
||||
abi: JsValue,
|
||||
args: JsValue,
|
||||
config: JsValue,
|
||||
) -> Result<ComputationResult, JsValue> {
|
||||
let prog = ir::ProgEnum::deserialize(program)
|
||||
.map_err(|err| JsValue::from_str(&err))?
|
||||
.collect();
|
||||
match prog {
|
||||
ProgEnum::Bn128Program(p) => internal::compute::<_>(p, abi, args),
|
||||
ProgEnum::Bls12_381Program(p) => internal::compute::<_>(p, abi, args),
|
||||
ProgEnum::Bls12_377Program(p) => internal::compute::<_>(p, abi, args),
|
||||
ProgEnum::Bw6_761Program(p) => internal::compute::<_>(p, abi, args),
|
||||
ProgEnum::Bn128Program(p) => internal::compute::<_>(p, abi, args, config),
|
||||
ProgEnum::Bls12_381Program(p) => internal::compute::<_>(p, abi, args, config),
|
||||
ProgEnum::Bls12_377Program(p) => internal::compute::<_>(p, abi, args, config),
|
||||
ProgEnum::Bw6_761Program(p) => internal::compute::<_>(p, abi, args, config),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
BIN
zokrates_js/tests/powersOfTau5_0000.ptau
Normal file
BIN
zokrates_js/tests/powersOfTau5_0000.ptau
Normal file
Binary file not shown.
|
@ -1,170 +1,235 @@
|
|||
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 } = require("../node/index.js");
|
||||
|
||||
describe("tests", function () {
|
||||
let zokratesProvider;
|
||||
let zokratesProvider;
|
||||
let tmpFolder;
|
||||
|
||||
describe("tests", () => {
|
||||
// initialize once before running tests
|
||||
before((done) => {
|
||||
initialize().then((defaultProvider) => {
|
||||
before(() => {
|
||||
return initialize().then((defaultProvider) => {
|
||||
zokratesProvider = defaultProvider;
|
||||
done();
|
||||
return fs.promises.mkdtemp(path.join(os.tmpdir(), path.sep)).then((folder) => {
|
||||
tmpFolder = folder;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("compilation", () => {
|
||||
it("should compile", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
const artifacts = zokratesProvider.compile(
|
||||
"def main() -> field { return 42; }"
|
||||
);
|
||||
assert.ok(artifacts !== undefined);
|
||||
});
|
||||
});
|
||||
after(() => {
|
||||
if (globalThis.curve_bn128) globalThis.curve_bn128.terminate();
|
||||
});
|
||||
|
||||
it("should throw on invalid code", () => {
|
||||
assert.throws(() => zokratesProvider.compile(":-)"));
|
||||
});
|
||||
describe("compilation", () => {
|
||||
it("should compile", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
const artifacts = zokratesProvider.compile(
|
||||
"def main() -> field: return 42"
|
||||
);
|
||||
assert.ok(artifacts !== undefined);
|
||||
assert.ok(artifacts.snarkjs === undefined);
|
||||
});
|
||||
});
|
||||
|
||||
it("should resolve stdlib module", () => {
|
||||
const stdlib = require("../stdlib.js");
|
||||
assert.doesNotThrow(() => {
|
||||
const code = `import "${
|
||||
Object.keys(stdlib)[0]
|
||||
}" as func; def main() { return; }`;
|
||||
zokratesProvider.compile(code);
|
||||
});
|
||||
});
|
||||
it("should compile with snarkjs output", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
const artifacts = zokratesProvider.compile(
|
||||
"def main() -> field: return 42",
|
||||
{ snarkjs: true }
|
||||
);
|
||||
assert.ok(artifacts !== undefined);
|
||||
assert.ok(artifacts.snarkjs.program !== undefined);
|
||||
});
|
||||
});
|
||||
|
||||
it("should resolve user module", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
const code =
|
||||
'import "test" as test; def 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 invalid code", () => {
|
||||
assert.throws(() => zokratesProvider.compile(":-)"));
|
||||
});
|
||||
|
||||
it("should throw on unresolved module", () => {
|
||||
assert.throws(() => {
|
||||
const code =
|
||||
'import "test" as test; def main() -> field { return test(); }';
|
||||
zokratesProvider.compile(code);
|
||||
});
|
||||
});
|
||||
});
|
||||
it("should resolve stdlib module", () => {
|
||||
const stdlib = require("../stdlib.js");
|
||||
assert.doesNotThrow(() => {
|
||||
const code = `import "${
|
||||
Object.keys(stdlib)[0]
|
||||
}" as func\ndef main(): return`;
|
||||
zokratesProvider.compile(code);
|
||||
});
|
||||
});
|
||||
|
||||
describe("computation", () => {
|
||||
it("should compute with valid inputs", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
const code = "def main(private field a) -> field { return a * a; }";
|
||||
const artifacts = 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 result = zokratesProvider.computeWitness(artifacts, ["2"]);
|
||||
const output = JSON.parse(result.output);
|
||||
assert.deepEqual(output, "4");
|
||||
});
|
||||
});
|
||||
it("should throw on unresolved module", () => {
|
||||
assert.throws(() => {
|
||||
const code =
|
||||
'import "test" as test\ndef main() -> field: return test()';
|
||||
zokratesProvider.compile(code);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should throw on invalid input count", () => {
|
||||
assert.throws(() => {
|
||||
const code = "def main(private field a) -> field { return a * a; }";
|
||||
const artifacts = zokratesProvider.compile(code);
|
||||
zokratesProvider.computeWitness(artifacts, ["1", "2"]);
|
||||
});
|
||||
});
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
it("should throw on invalid input type", () => {
|
||||
assert.throws(() => {
|
||||
const code = "def main(private field a) -> field { return a * a; }";
|
||||
const artifacts = zokratesProvider.compile(code);
|
||||
zokratesProvider.computeWitness(artifacts, [true]);
|
||||
});
|
||||
});
|
||||
});
|
||||
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 runWithOptions = (options) => {
|
||||
let provider;
|
||||
let artifacts;
|
||||
let computationResult;
|
||||
let keypair;
|
||||
let proof;
|
||||
const result = zokratesProvider.computeWitness(artifacts, ["2"], {
|
||||
snarkjs: true,
|
||||
});
|
||||
|
||||
before((done) => {
|
||||
provider = zokratesProvider.withOptions(options);
|
||||
done();
|
||||
});
|
||||
const output = JSON.parse(result.output);
|
||||
assert.deepEqual(output, ["4"]);
|
||||
assert.ok(result.snarkjs.witness !== undefined);
|
||||
});
|
||||
});
|
||||
|
||||
it("compile", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
const code =
|
||||
"def main(private field a, field b) -> bool { return a * a == b; }";
|
||||
artifacts = provider.compile(code);
|
||||
});
|
||||
});
|
||||
it("should throw on invalid input count", () => {
|
||||
assert.throws(() => {
|
||||
const code = "def main(private field a) -> field: return a * a";
|
||||
const artifacts = zokratesProvider.compile(code);
|
||||
zokratesProvider.computeWitness(artifacts, ["1", "2"]);
|
||||
});
|
||||
});
|
||||
|
||||
it("compute witness", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
computationResult = provider.computeWitness(artifacts, ["2", "4"]);
|
||||
});
|
||||
});
|
||||
it("should throw on invalid input type", () => {
|
||||
assert.throws(() => {
|
||||
const code = "def main(private field a) -> field: return a * a";
|
||||
const artifacts = zokratesProvider.compile(code);
|
||||
zokratesProvider.computeWitness(artifacts, [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);
|
||||
}
|
||||
});
|
||||
});
|
||||
const runWithOptions = (options) => {
|
||||
let provider;
|
||||
let artifacts;
|
||||
let computationResult;
|
||||
let keypair;
|
||||
let proof;
|
||||
|
||||
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"));
|
||||
});
|
||||
});
|
||||
}
|
||||
before(() => {
|
||||
provider = zokratesProvider.withOptions(options);
|
||||
});
|
||||
|
||||
it("generate proof", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
proof = provider.generateProof(
|
||||
artifacts.program,
|
||||
computationResult.witness,
|
||||
keypair.pk
|
||||
);
|
||||
assert.ok(proof !== undefined);
|
||||
assert.equal(proof.inputs.length, 2);
|
||||
});
|
||||
});
|
||||
it("compile", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
const code =
|
||||
"def main(private field a, field b) -> bool: return a * a == b";
|
||||
artifacts = provider.compile(code, { snarkjs: true });
|
||||
});
|
||||
});
|
||||
|
||||
it("verify", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
assert(provider.verify(keypair.vk, proof) === true);
|
||||
});
|
||||
});
|
||||
};
|
||||
it("compute witness", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
computationResult = provider.computeWitness(artifacts, ["2", "4"], {
|
||||
snarkjs: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
for (const scheme of ["g16", "gm17", "marlin"]) {
|
||||
describe(scheme, () => {
|
||||
for (const curve of ["bn128", "bls12_381", "bls12_377", "bw6_761"]) {
|
||||
describe(curve, () => runWithOptions({ scheme, curve }));
|
||||
}
|
||||
});
|
||||
}
|
||||
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 === "g16" && options.curve == "bn128") {
|
||||
it("snarkjs setup", () => {
|
||||
// write program to fs
|
||||
let r1csPath = tmpFolder + "/prog.r1cs";
|
||||
let zkeyPath = tmpFolder + "/key.zkey";
|
||||
return fs.promises
|
||||
.writeFile(r1csPath, artifacts.snarkjs.program)
|
||||
.then(() => {
|
||||
return snarkjs.zKey
|
||||
.newZKey(r1csPath, "./tests/powersOfTau5_0000.ptau", zkeyPath)
|
||||
.then(() => {});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
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"));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
it("generate proof", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
proof = provider.generateProof(
|
||||
artifacts.program,
|
||||
computationResult.witness,
|
||||
keypair.pk
|
||||
);
|
||||
assert.ok(proof !== undefined);
|
||||
assert.equal(proof.inputs.length, 2);
|
||||
});
|
||||
});
|
||||
|
||||
if (options.scheme === "g16" && options.curve == "bn128") {
|
||||
it("generate snarkjs proof", () => {
|
||||
// write witness to fs
|
||||
let witnessPath = tmpFolder + "/witness.wtns";
|
||||
let zkeyPath = tmpFolder + "/key.zkey";
|
||||
return fs.promises
|
||||
.writeFile(witnessPath, computationResult.snarkjs.witness)
|
||||
.then(() => {
|
||||
return snarkjs.groth16.prove(zkeyPath, witnessPath);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
it("verify", () => {
|
||||
assert.doesNotThrow(() => {
|
||||
assert(provider.verify(keypair.vk, proof) === true);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
for (const scheme of ["g16", "gm17", "marlin"]) {
|
||||
describe(scheme, () => {
|
||||
for (const curve of ["bn128", "bls12_381", "bls12_377", "bw6_761"]) {
|
||||
describe(curve, () => runWithOptions({ scheme, curve }));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const testRunner = (rootPath, testPath, test) => {
|
||||
let entryPoint;
|
||||
|
@ -241,7 +306,7 @@ describe("tests", function () {
|
|||
const test = require(file.path);
|
||||
const testName = file.path.substring(testsPath.length + 1);
|
||||
|
||||
if (!ignoreList.some(v => testName.startsWith(v)))
|
||||
if (!ignoreList.some((v) => testName.startsWith(v)))
|
||||
describe(testName, () => testRunner(rootPath, file.path, test));
|
||||
});
|
||||
});
|
||||
|
|
|
@ -35,12 +35,16 @@ module.exports = (dep) => {
|
|||
|
||||
const defaultProvider = {
|
||||
compile: (source, compileOptions = {}) => {
|
||||
const {
|
||||
var {
|
||||
curve = "bn128",
|
||||
location = "main.zok",
|
||||
resolveCallback = () => null,
|
||||
config = {},
|
||||
snarkjs = false,
|
||||
} = compileOptions;
|
||||
|
||||
config = { snarkjs, ...config };
|
||||
|
||||
const callback = (currentLocation, importLocation) => {
|
||||
return (
|
||||
resolveFromStdlib(currentLocation, importLocation) ||
|
||||
|
@ -48,15 +52,36 @@ module.exports = (dep) => {
|
|||
);
|
||||
};
|
||||
const ptr = zokrates.compile(source, location, callback, config, curve);
|
||||
return {
|
||||
program: ptr.program(),
|
||||
abi: ptr.abi(),
|
||||
};
|
||||
return Object.assign(
|
||||
{
|
||||
program: ptr.program(),
|
||||
abi: ptr.abi(),
|
||||
},
|
||||
snarkjs ? { snarkjs: { program: ptr.snarkjs_program() } } : {}
|
||||
);
|
||||
},
|
||||
computeWitness: (input, args) => {
|
||||
computeWitness: (input, args, computeOptions = {}) => {
|
||||
const { program, abi } =
|
||||
input instanceof Uint8Array ? { program: input, abi: null } : input;
|
||||
return zokrates.compute_witness(program, abi, JSON.stringify(args));
|
||||
|
||||
const { snarkjs = false } = computeOptions;
|
||||
const ptr = zokrates.compute_witness(program, abi, JSON.stringify(args), {
|
||||
snarkjs: snarkjs,
|
||||
});
|
||||
|
||||
return Object.assign(
|
||||
{
|
||||
witness: ptr.witness(),
|
||||
output: ptr.output(),
|
||||
},
|
||||
snarkjs
|
||||
? {
|
||||
snarkjs: {
|
||||
witness: ptr.snarkjs_witness(),
|
||||
},
|
||||
}
|
||||
: {}
|
||||
);
|
||||
},
|
||||
setup: (program, options) => {
|
||||
return zokrates.setup(program, options);
|
||||
|
@ -79,8 +104,8 @@ module.exports = (dep) => {
|
|||
utils: {
|
||||
formatProof: (proof) => {
|
||||
return zokrates.format_proof(proof);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const withOptions = (options) => {
|
||||
|
@ -91,8 +116,8 @@ module.exports = (dep) => {
|
|||
...compileOptions,
|
||||
curve: options.curve,
|
||||
}),
|
||||
computeWitness: (artifacts, args) =>
|
||||
defaultProvider.computeWitness(artifacts, args),
|
||||
computeWitness: (artifacts, args, computeOptions = {}) =>
|
||||
defaultProvider.computeWitness(artifacts, args, computeOptions),
|
||||
setup: (program) => defaultProvider.setup(program, options),
|
||||
universalSetup: (size) =>
|
||||
defaultProvider.universalSetup(options.curve, size),
|
||||
|
@ -105,11 +130,11 @@ module.exports = (dep) => {
|
|||
defaultProvider.exportSolidityVerifier(vk),
|
||||
utils: {
|
||||
formatProof: (proof) => defaultProvider.utils.formatProof(proof),
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
return {
|
||||
...withOptions({ scheme: "g16", curve: "bn128" }),
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use primitive_types::U256;
|
||||
pub use revm::Return;
|
||||
use revm::{AccountInfo, InMemoryDB, Log, TransactOut, TransactTo, EVM};
|
||||
use revm::{AccountInfo, Database, InMemoryDB, Log, TransactOut, TransactTo, EVM};
|
||||
|
||||
use crate::{address::Address, Error, EvmTestError};
|
||||
|
||||
|
@ -60,31 +60,18 @@ impl Evm {
|
|||
contract: Vec<u8>,
|
||||
deployer: &Address,
|
||||
) -> Result<CreateContractResult, Error> {
|
||||
match self
|
||||
.vm
|
||||
.db()
|
||||
.unwrap()
|
||||
.cache()
|
||||
.get_key_value(deployer.as_ref())
|
||||
{
|
||||
Some(_) => {
|
||||
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,
|
||||
})
|
||||
}
|
||||
None => Err(Box::new(EvmTestError(
|
||||
"deployer address not found".to_string(),
|
||||
))),
|
||||
}
|
||||
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>) {
|
||||
|
@ -97,27 +84,17 @@ impl Evm {
|
|||
address: &Address,
|
||||
balance: impl Into<U256>,
|
||||
) -> Result<(), Error> {
|
||||
let mut acc = self
|
||||
.vm
|
||||
.db()
|
||||
.unwrap()
|
||||
.cache()
|
||||
.get(address.as_ref())
|
||||
.ok_or_else(|| Box::new(EvmTestError("account address not found".to_string())))?
|
||||
.clone();
|
||||
let mut acc = self.vm.db().unwrap().basic(*address.as_ref()).clone();
|
||||
acc.balance = balance.into();
|
||||
self.vm.db().unwrap().insert_cache(*address.as_ref(), acc);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn balance_of(&mut self, address: &Address) -> U256 {
|
||||
match self.vm.db().unwrap().cache().get(address.as_ref()) {
|
||||
Some(acc) => acc.balance,
|
||||
None => 0.into(),
|
||||
}
|
||||
self.vm.db().unwrap().basic(*address.as_ref()).balance
|
||||
}
|
||||
|
||||
pub fn get_account(&mut self, address: &Address) -> Option<AccountInfo> {
|
||||
self.vm.db().unwrap().cache().get(address.as_ref()).cloned()
|
||||
pub fn get_account(&mut self, address: &Address) -> AccountInfo {
|
||||
self.vm.db().unwrap().basic(*address.as_ref())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_stdlib"
|
||||
version = "0.2.8"
|
||||
version = "0.2.9"
|
||||
authors = ["Stefan Deml <stefandeml@gmail.com>", "schaeff <thibaut@schaeff.fr>"]
|
||||
edition = "2018"
|
||||
|
||||
|
|
Loading…
Reference in a new issue