1
0
Fork 0
mirror of synced 2025-09-23 04:08:33 +00:00
This commit is contained in:
dark64 2020-12-28 18:18:29 +01:00
parent 5595cf16ca
commit f68d887038
9 changed files with 552 additions and 161 deletions

69
Cargo.lock generated
View file

@ -210,6 +210,15 @@ version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
[[package]]
name = "arrayvec"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9"
dependencies = [
"nodrop",
]
[[package]]
name = "arrayvec"
version = "0.5.2"
@ -324,6 +333,17 @@ dependencies = [
"opaque-debug",
]
[[package]]
name = "blake2-rfc_bellman_edition"
version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdc60350286c7c3db13b98e91dbe5c8b6830a6821bc20af5b0c310ce94d74915"
dependencies = [
"arrayvec 0.4.12",
"byteorder",
"constant_time_eq",
]
[[package]]
name = "blake2b_simd"
version = "0.5.11"
@ -331,7 +351,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587"
dependencies = [
"arrayref",
"arrayvec",
"arrayvec 0.5.2",
"constant_time_eq",
]
@ -559,6 +579,12 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "crypto-mac"
version = "0.7.0"
@ -1077,6 +1103,12 @@ dependencies = [
"autocfg",
]
[[package]]
name = "nodrop"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
[[package]]
name = "num"
version = "0.1.42"
@ -1563,6 +1595,23 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "sapling-crypto_ce"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c4ff5309ec3e4bd800ad4ab3f71e9b76e9ea81c9f0eda6efa16008afbe440b3"
dependencies = [
"bellman_ce",
"blake2-rfc_bellman_edition",
"byteorder",
"digest",
"rand 0.4.6",
"serde",
"serde_derive",
"sha2",
"tiny-keccak",
]
[[package]]
name = "scoped-tls"
version = "1.0.0"
@ -1782,6 +1831,15 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "tiny-keccak"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
dependencies = [
"crunchy",
]
[[package]]
name = "tinyvec"
version = "1.1.0"
@ -2156,6 +2214,7 @@ dependencies = [
"typed-arena",
"wasm-bindgen-test",
"zokrates_common",
"zokrates_embed",
"zokrates_field",
"zokrates_pest_ast",
]
@ -2168,6 +2227,14 @@ dependencies = [
"zokrates_test_derive",
]
[[package]]
name = "zokrates_embed"
version = "0.1.1"
dependencies = [
"bellman_ce",
"sapling-crypto_ce",
]
[[package]]
name = "zokrates_field"
version = "0.3.7"

View file

@ -6,6 +6,7 @@ members = [
"zokrates_cli",
"zokrates_fs_resolver",
"zokrates_stdlib",
"zokrates_embed",
"zokrates_abi",
"zokrates_test",
"zokrates_core_test",

View file

@ -31,6 +31,7 @@ regex = "0.2"
zokrates_field = { version = "0.3.0", path = "../zokrates_field", default-features = false }
zokrates_pest_ast = { version = "0.1.0", path = "../zokrates_pest_ast" }
zokrates_common = { path = "../zokrates_common" }
zokrates_embed = { path = "../zokrates_embed" }
rand_0_4 = { version = "0.4", package = "rand" }
rand_0_7 = { version = "0.7", package = "rand" }
csv = "1"

View file

@ -10,8 +10,7 @@ mod utils;
use self::utils::flat_expression_from_bits;
use crate::flat_absy::*;
use crate::ir;
use crate::solvers::Solver;
use crate::solvers::{Executable, Solver};
use crate::zir::types::{FunctionIdentifier, FunctionKey, Signature, Type, UBitwidth};
use crate::zir::*;
use std::collections::hash_map::Entry;
@ -1652,8 +1651,9 @@ impl<'ast, T: Field> Flattener<'ast, T> {
// constants do not require directives
match e.field {
Some(FlatExpression::Number(ref x)) => {
let bits: Vec<_> = ir::Interpreter::default()
.execute_solver(&Solver::bits(to), &vec![x.clone()])
let solver = Solver::bits(to);
let bits: Vec<_> = solver
.execute(&vec![x.clone()])
.unwrap()
.into_iter()
.map(|x| FlatExpression::Number(x))

View file

@ -1,7 +1,7 @@
use crate::flat_absy::flat_variable::FlatVariable;
use crate::ir::Directive;
use crate::ir::{LinComb, Prog, QuadComb, Statement, Witness};
use crate::solvers::Solver;
use crate::solvers::{Executable, Solver};
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::fmt;
@ -76,7 +76,7 @@ impl Interpreter {
.iter()
.map(|i| i.evaluate(&witness).unwrap())
.collect();
match self.execute_solver(&d.solver, &inputs) {
match d.solver.execute(&inputs) {
Ok(res) => {
for (i, o) in d.outputs.iter().enumerate() {
witness.insert(o.clone(), res[i].clone());
@ -134,79 +134,6 @@ impl Interpreter {
})
}
}
pub fn execute_solver<T: Field>(&self, s: &Solver, inputs: &Vec<T>) -> Result<Vec<T>, String> {
let (expected_input_count, expected_output_count) = s.get_signature();
assert!(inputs.len() == expected_input_count);
let res = match s {
Solver::ConditionEq => match inputs[0].is_zero() {
true => vec![T::zero(), T::one()],
false => vec![
T::one(),
T::one().checked_div(&inputs[0]).unwrap_or(T::one()),
],
},
Solver::Bits(bit_width) => {
let mut num = inputs[0].clone();
let mut res = vec![];
for i in (0..*bit_width).rev() {
if T::from(2).pow(i) <= num {
num = num - T::from(2).pow(i);
res.push(T::one());
} else {
res.push(T::zero());
}
}
res
}
Solver::Xor => {
let x = inputs[0].clone();
let y = inputs[1].clone();
vec![x.clone() + y.clone() - T::from(2) * x * y]
}
Solver::Or => {
let x = inputs[0].clone();
let y = inputs[1].clone();
vec![x.clone() + y.clone() - x * y]
}
// res = b * c - (2b * c - b - c) * (a)
Solver::ShaAndXorAndXorAnd => {
let a = inputs[0].clone();
let b = inputs[1].clone();
let c = inputs[2].clone();
vec![b.clone() * c.clone() - (T::from(2) * b.clone() * c.clone() - b - c) * a]
}
// res = a(b - c) + c
Solver::ShaCh => {
let a = inputs[0].clone();
let b = inputs[1].clone();
let c = inputs[2].clone();
vec![a * (b - c.clone()) + c]
}
Solver::Div => vec![inputs[0]
.clone()
.checked_div(&inputs[1])
.unwrap_or(T::one())],
Solver::EuclideanDiv => {
use num::CheckedDiv;
let n = inputs[0].clone().to_biguint();
let d = inputs[1].clone().to_biguint();
let q = n.checked_div(&d).unwrap_or(0u32.into());
let r = n - d * &q;
vec![T::try_from(q).unwrap(), T::try_from(r).unwrap()]
}
};
assert_eq!(res.len(), expected_output_count);
Ok(res)
}
}
impl<T: Field> LinComb<T> {
@ -265,77 +192,3 @@ impl fmt::Debug for Error {
write!(f, "{}", self)
}
}
#[cfg(test)]
mod tests {
use super::*;
use zokrates_field::Bn128Field;
mod eq_condition {
// Wanted: (Y = (X != 0) ? 1 : 0)
// # Y = if X == 0 then 0 else 1 fi
// # M = if X == 0 then 1 else 1/X fi
use super::*;
#[test]
fn execute() {
let cond_eq = Solver::ConditionEq;
let inputs = vec![0];
let interpreter = Interpreter::default();
let r = interpreter
.execute_solver(
&cond_eq,
&inputs.iter().map(|&i| Bn128Field::from(i)).collect(),
)
.unwrap();
let res: Vec<Bn128Field> = vec![0, 1].iter().map(|&i| Bn128Field::from(i)).collect();
assert_eq!(r, &res[..]);
}
#[test]
fn execute_non_eq() {
let cond_eq = Solver::ConditionEq;
let inputs = vec![1];
let interpreter = Interpreter::default();
let r = interpreter
.execute_solver(
&cond_eq,
&inputs.iter().map(|&i| Bn128Field::from(i)).collect(),
)
.unwrap();
let res: Vec<Bn128Field> = vec![1, 1].iter().map(|&i| Bn128Field::from(i)).collect();
assert_eq!(r, &res[..]);
}
}
#[test]
fn bits_of_one() {
let inputs = vec![Bn128Field::from(1)];
let interpreter = Interpreter::default();
let res = interpreter
.execute_solver(&Solver::Bits(Bn128Field::get_required_bits()), &inputs)
.unwrap();
assert_eq!(res[253], Bn128Field::from(1));
for i in 0..253 {
assert_eq!(res[i], Bn128Field::from(0));
}
}
#[test]
fn bits_of_42() {
let inputs = vec![Bn128Field::from(42)];
let interpreter = Interpreter::default();
let res = interpreter
.execute_solver(&Solver::Bits(Bn128Field::get_required_bits()), &inputs)
.unwrap();
assert_eq!(res[253], Bn128Field::from(0));
assert_eq!(res[252], Bn128Field::from(1));
assert_eq!(res[251], Bn128Field::from(0));
assert_eq!(res[250], Bn128Field::from(1));
assert_eq!(res[249], Bn128Field::from(0));
assert_eq!(res[248], Bn128Field::from(1));
assert_eq!(res[247], Bn128Field::from(0));
}
}

View file

@ -40,6 +40,7 @@ use crate::flat_absy::flat_variable::FlatVariable;
use crate::ir::folder::{fold_function, Folder};
use crate::ir::LinComb;
use crate::ir::*;
use crate::solvers::Executable;
use std::collections::{HashMap, HashSet};
use zokrates_field::Field;
@ -146,10 +147,8 @@ impl<T: Field> Folder<T> for RedefinitionOptimizer<T> {
true => {
// unwrap inputs to their constant value
let inputs = inputs.into_iter().map(|i| i.unwrap()).collect();
// run the interpereter
let outputs = Interpreter::default()
.execute_solver(&d.solver, &inputs)
.unwrap();
// run the solver
let outputs = d.solver.execute(&inputs).unwrap();
assert_eq!(outputs.len(), d.outputs.len());

View file

@ -12,6 +12,7 @@ pub enum Solver {
ShaAndXorAndXorAnd,
ShaCh,
EuclideanDiv,
Sha256Round,
}
impl fmt::Display for Solver {
@ -31,6 +32,7 @@ impl Solver {
Solver::ShaAndXorAndXorAnd => (3, 1),
Solver::ShaCh => (3, 1),
Solver::EuclideanDiv => (2, 2),
Solver::Sha256Round => (768, 26935),
}
}
}
@ -41,10 +43,145 @@ impl Solver {
}
}
pub trait Executable<T: Field>: Signed {
pub trait Executable<T> {
fn execute(&self, inputs: &Vec<T>) -> Result<Vec<T>, String>;
}
pub trait Signed {
fn get_signature(&self) -> (usize, usize);
impl<T: Field> Executable<T> for Solver {
fn execute(&self, inputs: &Vec<T>) -> Result<Vec<T>, String> {
let (expected_input_count, expected_output_count) = self.get_signature();
assert_eq!(inputs.len(), expected_input_count);
let res = match self {
Solver::ConditionEq => match inputs[0].is_zero() {
true => vec![T::zero(), T::one()],
false => vec![
T::one(),
T::one().checked_div(&inputs[0]).unwrap_or(T::one()),
],
},
Solver::Bits(bit_width) => {
let mut num = inputs[0].clone();
let mut res = vec![];
for i in (0..*bit_width).rev() {
if T::from(2).pow(i) <= num {
num = num - T::from(2).pow(i);
res.push(T::one());
} else {
res.push(T::zero());
}
}
res
}
Solver::Xor => {
let x = inputs[0].clone();
let y = inputs[1].clone();
vec![x.clone() + y.clone() - T::from(2) * x * y]
}
Solver::Or => {
let x = inputs[0].clone();
let y = inputs[1].clone();
vec![x.clone() + y.clone() - x * y]
}
// res = b * c - (2b * c - b - c) * (a)
Solver::ShaAndXorAndXorAnd => {
let a = inputs[0].clone();
let b = inputs[1].clone();
let c = inputs[2].clone();
vec![b.clone() * c.clone() - (T::from(2) * b.clone() * c.clone() - b - c) * a]
}
// res = a(b - c) + c
Solver::ShaCh => {
let a = inputs[0].clone();
let b = inputs[1].clone();
let c = inputs[2].clone();
vec![a * (b - c.clone()) + c]
}
Solver::Div => vec![inputs[0]
.clone()
.checked_div(&inputs[1])
.unwrap_or(T::one())],
Solver::EuclideanDiv => {
use num::CheckedDiv;
let n = inputs[0].clone().to_biguint();
let d = inputs[1].clone().to_biguint();
let q = n.checked_div(&d).unwrap_or(0u32.into());
let r = n - d * &q;
vec![T::try_from(q).unwrap(), T::try_from(r).unwrap()]
}
_ => unimplemented!(),
};
assert_eq!(res.len(), expected_output_count);
Ok(res)
}
}
#[cfg(test)]
mod tests {
use super::*;
use zokrates_field::Bn128Field;
mod eq_condition {
// Wanted: (Y = (X != 0) ? 1 : 0)
// # Y = if X == 0 then 0 else 1 fi
// # M = if X == 0 then 1 else 1/X fi
use super::*;
#[test]
fn execute() {
let cond_eq = Solver::ConditionEq;
let inputs = vec![0];
let r = cond_eq
.execute(&inputs.iter().map(|&i| Bn128Field::from(i)).collect())
.unwrap();
let res: Vec<Bn128Field> = vec![0, 1].iter().map(|&i| Bn128Field::from(i)).collect();
assert_eq!(r, &res[..]);
}
#[test]
fn execute_non_eq() {
let cond_eq = Solver::ConditionEq;
let inputs = vec![1];
let r = cond_eq
.execute(&inputs.iter().map(|&i| Bn128Field::from(i)).collect())
.unwrap();
let res: Vec<Bn128Field> = vec![1, 1].iter().map(|&i| Bn128Field::from(i)).collect();
assert_eq!(r, &res[..]);
}
}
#[test]
fn bits_of_one() {
let bits = Solver::Bits(Bn128Field::get_required_bits());
let inputs = vec![Bn128Field::from(1)];
let res = bits.execute(&inputs).unwrap();
assert_eq!(res[253], Bn128Field::from(1));
for i in 0..253 {
assert_eq!(res[i], Bn128Field::from(0));
}
}
#[test]
fn bits_of_42() {
let bits = Solver::Bits(Bn128Field::get_required_bits());
let inputs = vec![Bn128Field::from(42)];
let res = bits.execute(&inputs).unwrap();
assert_eq!(res[253], Bn128Field::from(0));
assert_eq!(res[252], Bn128Field::from(1));
assert_eq!(res[251], Bn128Field::from(0));
assert_eq!(res[250], Bn128Field::from(1));
assert_eq!(res[249], Bn128Field::from(0));
assert_eq!(res[248], Bn128Field::from(1));
assert_eq!(res[247], Bn128Field::from(0));
}
}

14
zokrates_embed/Cargo.toml Normal file
View file

@ -0,0 +1,14 @@
[package]
name = "zokrates_embed"
version = "0.1.1"
authors = ["schaeff <thibaut@schaeff.fr>"]
edition = "2018"
[features]
default = []
wasm = ["bellman_ce/wasm", "sapling-crypto_ce/wasm"]
multicore = ["bellman_ce/multicore", "sapling-crypto_ce/multicore"]
[dependencies]
bellman_ce = { version = "^0.3", default-features = false }
sapling-crypto_ce = { version = "^0.1", default-features = false }

319
zokrates_embed/src/lib.rs Normal file
View file

@ -0,0 +1,319 @@
extern crate sapling_crypto_ce as sapling_crypto;
use sapling_crypto::bellman;
use bellman::{
pairing::{ff::Field, Engine},
ConstraintSystem, Index, LinearCombination, SynthesisError, Variable,
};
use sapling_crypto::circuit::{
boolean::{AllocatedBit, Boolean},
sha256::sha256_compression_function,
uint32::UInt32,
};
#[derive(Debug)]
pub struct BellmanR1CS<E: Engine> {
pub aux_count: usize,
pub constraints: Vec<BellmanConstraint<E>>,
}
impl<E: Engine> BellmanR1CS<E> {
pub fn new() -> Self {
BellmanR1CS {
aux_count: 0,
constraints: vec![],
}
}
}
#[derive(Debug)]
pub struct BellmanWitness<E: Engine> {
pub values: Vec<E::Fr>,
}
#[derive(Debug, PartialEq)]
pub struct BellmanConstraint<E: Engine> {
pub a: Vec<(usize, E::Fr)>,
pub b: Vec<(usize, E::Fr)>,
pub c: Vec<(usize, E::Fr)>,
}
fn sha256_round<E: Engine, CS: ConstraintSystem<E>>(
mut cs: CS,
input: &Vec<Option<E::Fr>>,
current_hash: &Vec<Option<E::Fr>>,
) -> Result<(Vec<usize>, Vec<usize>, Vec<usize>), SynthesisError> {
// Allocate bits for `input`
let input_bits = input
.iter()
.enumerate()
.map(|(index, i)| {
AllocatedBit::alloc::<E, _>(
&mut cs.namespace(|| format!("input_{}", index)),
Some(*i == Some(<E::Fr as Field>::one())),
)
.unwrap()
})
.collect::<Vec<_>>();
// Define Booleans whose values are the defined bits
let input = input_bits
.iter()
.map(|i| Boolean::Is(i.clone()))
.collect::<Vec<_>>();
// Allocate bits for `current_hash`
let current_hash_bits = current_hash
.iter()
.enumerate()
.map(|(index, i)| {
AllocatedBit::alloc::<E, _>(
&mut cs.namespace(|| format!("current_hash_{}", index)),
Some(*i == Some(<E::Fr as Field>::one())),
)
.unwrap()
})
.collect::<Vec<_>>();
// Define Booleans whose values are the defined bits
let current_hash = current_hash_bits
.chunks(32)
.map(|chunk| {
UInt32::from_bits_be(
&chunk
.into_iter()
.map(|i| Boolean::Is(i.clone()))
.collect::<Vec<_>>(),
)
})
.collect::<Vec<_>>();
// Apply the compression function, returning the 8 bytes of outputs
let res = sha256_compression_function::<E, _>(&mut cs, &input, &current_hash).unwrap();
// Extract the 256 bits of output out of the 8 bytes
let output_bits = res
.into_iter()
.flat_map(|u| u.into_bits_be())
.map(|b| b.get_variable().unwrap().clone())
.collect::<Vec<_>>();
// Return indices of `input`, `current_hash` and `output` in the CS
Ok((
input_bits
.into_iter()
.map(|b| var_to_index(b.get_variable()))
.collect(),
current_hash_bits
.into_iter()
.map(|b| var_to_index(b.get_variable()))
.collect(),
output_bits
.into_iter()
.map(|b| var_to_index(b.get_variable()))
.collect(),
))
}
impl<E: Engine> ConstraintSystem<E> for BellmanWitness<E> {
type Root = Self;
fn alloc<F, A, AR>(&mut self, _: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
let index = self.values.len();
let var = Variable::new_unchecked(Index::Aux(index));
self.values.push(f().unwrap());
Ok(var)
}
fn alloc_input<F, A, AR>(&mut self, _: A, _: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
unreachable!("Bellman helpers are not allowed to allocate public variables")
}
fn enforce<A, AR, LA, LB, LC>(&mut self, _: A, _: LA, _: LB, _: LC)
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
{
// do nothing
}
fn push_namespace<NR, N>(&mut self, _: N)
where
NR: Into<String>,
N: FnOnce() -> NR,
{
// do nothing
}
fn pop_namespace(&mut self) {
// do nothing
}
fn get_root(&mut self) -> &mut Self::Root {
self
}
}
impl<E: Engine> ConstraintSystem<E> for BellmanR1CS<E> {
type Root = Self;
fn alloc<F, A, AR>(&mut self, _: A, _: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
// we don't care about the value as we're only generating the CS
let index = self.aux_count;
let var = Variable::new_unchecked(Index::Aux(index));
self.aux_count += 1;
Ok(var)
}
fn alloc_input<F, A, AR>(&mut self, _: A, _: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
unreachable!("Bellman helpers are not allowed to allocate public variables")
}
fn enforce<A, AR, LA, LB, LC>(&mut self, _: A, a: LA, b: LB, c: LC)
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
{
let a = a(LinearCombination::zero());
let b = b(LinearCombination::zero());
let c = c(LinearCombination::zero());
let a = a
.as_ref()
.into_iter()
.map(|(variable, coefficient)| (var_to_index(*variable), *coefficient))
.collect();
let b = b
.as_ref()
.into_iter()
.map(|(variable, coefficient)| (var_to_index(*variable), *coefficient))
.collect();
let c = c
.as_ref()
.into_iter()
.map(|(variable, coefficient)| (var_to_index(*variable), *coefficient))
.collect();
self.constraints.push(BellmanConstraint { a, b, c });
}
fn push_namespace<NR, N>(&mut self, _: N)
where
NR: Into<String>,
N: FnOnce() -> NR,
{
// do nothing
}
fn pop_namespace(&mut self) {
// do nothing
}
fn get_root(&mut self) -> &mut Self::Root {
self
}
}
pub fn generate_sha256_round_constraints<E: Engine>(
) -> (BellmanR1CS<E>, Vec<usize>, Vec<usize>, Vec<usize>) {
let mut cs = BellmanR1CS::new();
let (input_bits, current_hash_bits, output_bits) =
sha256_round(&mut cs, &vec![None; 512], &vec![None; 256]).unwrap();
// res is now the allocated bits for `input`, `current_hash` and `sha256_output`
(cs, input_bits, current_hash_bits, output_bits)
}
pub fn generate_sha256_round_witness<E: Engine>(
input: &[E::Fr],
current_hash: &[E::Fr],
) -> Vec<E::Fr> {
assert_eq!(input.len(), 512);
assert_eq!(current_hash.len(), 256);
let mut cs: BellmanWitness<E> = BellmanWitness {
values: vec![<E::Fr as Field>::one()],
};
sha256_round(
&mut cs,
&input.iter().map(|x| Some(x.clone())).collect(),
&current_hash.iter().map(|x| Some(x.clone())).collect(),
)
.unwrap();
cs.values
}
fn var_to_index(v: Variable) -> usize {
match v.get_unchecked() {
Index::Aux(i) => i + 1,
Index::Input(0) => 0,
_ => unreachable!("No public variables should have been allocated"),
}
}
#[cfg(test)]
mod tests {
use super::*;
use bellman::pairing::bn256::{Bn256, Fr};
#[test]
fn generate_constraints() {
let (_c, input, current_hash, output) = generate_sha256_round_constraints::<Bn256>();
assert_eq!(input.len(), 512);
assert_eq!(current_hash.len(), 256);
assert_eq!(output.len(), 256);
}
#[test]
fn generate_witness() {
let witness =
generate_sha256_round_witness::<Bn256>(&vec![Fr::one(); 512], &vec![Fr::zero(); 256]);
assert_eq!(witness.len(), 26935);
}
#[test]
fn test_cs() {
use sapling_crypto::circuit::test::TestConstraintSystem;
let mut cs: TestConstraintSystem<Bn256> = TestConstraintSystem::new();
let _ = sha256_round(
&mut cs,
&vec![Some(Fr::zero()); 512],
&vec![Some(Fr::one()); 256],
)
.unwrap();
assert!(cs.is_satisfied());
}
}