cargo fmt bellman
This commit is contained in:
parent
dfb86fcf11
commit
e73d1a2637
101
src/domain.rs
101
src/domain.rs
|
@ -13,9 +13,7 @@
|
|||
use ff::{Field, PrimeField, ScalarEngine};
|
||||
use group::CurveProjective;
|
||||
|
||||
use super::{
|
||||
SynthesisError
|
||||
};
|
||||
use super::SynthesisError;
|
||||
|
||||
use super::multicore::Worker;
|
||||
|
||||
|
@ -25,7 +23,7 @@ pub struct EvaluationDomain<E: ScalarEngine, G: Group<E>> {
|
|||
omega: E::Fr,
|
||||
omegainv: E::Fr,
|
||||
geninv: E::Fr,
|
||||
minv: E::Fr
|
||||
minv: E::Fr,
|
||||
}
|
||||
|
||||
impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
|
||||
|
@ -41,8 +39,7 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
|
|||
self.coeffs
|
||||
}
|
||||
|
||||
pub fn from_coeffs(mut coeffs: Vec<G>) -> Result<EvaluationDomain<E, G>, SynthesisError>
|
||||
{
|
||||
pub fn from_coeffs(mut coeffs: Vec<G>) -> Result<EvaluationDomain<E, G>, SynthesisError> {
|
||||
// Compute the size of our evaluation domain
|
||||
let mut m = 1;
|
||||
let mut exp = 0;
|
||||
|
@ -53,7 +50,7 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
|
|||
// The pairing-friendly curve may not be able to support
|
||||
// large enough (radix2) evaluation domains.
|
||||
if exp >= E::Fr::S {
|
||||
return Err(SynthesisError::PolynomialDegreeTooLarge)
|
||||
return Err(SynthesisError::PolynomialDegreeTooLarge);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,17 +69,18 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
|
|||
omega: omega,
|
||||
omegainv: omega.inverse().unwrap(),
|
||||
geninv: E::Fr::multiplicative_generator().inverse().unwrap(),
|
||||
minv: E::Fr::from_str(&format!("{}", m)).unwrap().inverse().unwrap()
|
||||
minv: E::Fr::from_str(&format!("{}", m))
|
||||
.unwrap()
|
||||
.inverse()
|
||||
.unwrap(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn fft(&mut self, worker: &Worker)
|
||||
{
|
||||
pub fn fft(&mut self, worker: &Worker) {
|
||||
best_fft(&mut self.coeffs, worker, &self.omega, self.exp);
|
||||
}
|
||||
|
||||
pub fn ifft(&mut self, worker: &Worker)
|
||||
{
|
||||
pub fn ifft(&mut self, worker: &Worker) {
|
||||
best_fft(&mut self.coeffs, worker, &self.omegainv, self.exp);
|
||||
|
||||
worker.scope(self.coeffs.len(), |scope, chunk| {
|
||||
|
@ -98,8 +96,7 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn distribute_powers(&mut self, worker: &Worker, g: E::Fr)
|
||||
{
|
||||
pub fn distribute_powers(&mut self, worker: &Worker, g: E::Fr) {
|
||||
worker.scope(self.coeffs.len(), |scope, chunk| {
|
||||
for (i, v) in self.coeffs.chunks_mut(chunk).enumerate() {
|
||||
scope.spawn(move || {
|
||||
|
@ -113,14 +110,12 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn coset_fft(&mut self, worker: &Worker)
|
||||
{
|
||||
pub fn coset_fft(&mut self, worker: &Worker) {
|
||||
self.distribute_powers(worker, E::Fr::multiplicative_generator());
|
||||
self.fft(worker);
|
||||
}
|
||||
|
||||
pub fn icoset_fft(&mut self, worker: &Worker)
|
||||
{
|
||||
pub fn icoset_fft(&mut self, worker: &Worker) {
|
||||
let geninv = self.geninv;
|
||||
|
||||
self.ifft(worker);
|
||||
|
@ -139,9 +134,11 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
|
|||
/// The target polynomial is the zero polynomial in our
|
||||
/// evaluation domain, so we must perform division over
|
||||
/// a coset.
|
||||
pub fn divide_by_z_on_coset(&mut self, worker: &Worker)
|
||||
{
|
||||
let i = self.z(&E::Fr::multiplicative_generator()).inverse().unwrap();
|
||||
pub fn divide_by_z_on_coset(&mut self, worker: &Worker) {
|
||||
let i = self
|
||||
.z(&E::Fr::multiplicative_generator())
|
||||
.inverse()
|
||||
.unwrap();
|
||||
|
||||
worker.scope(self.coeffs.len(), |scope, chunk| {
|
||||
for v in self.coeffs.chunks_mut(chunk) {
|
||||
|
@ -159,7 +156,11 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
|
|||
assert_eq!(self.coeffs.len(), other.coeffs.len());
|
||||
|
||||
worker.scope(self.coeffs.len(), |scope, chunk| {
|
||||
for (a, b) in self.coeffs.chunks_mut(chunk).zip(other.coeffs.chunks(chunk)) {
|
||||
for (a, b) in self
|
||||
.coeffs
|
||||
.chunks_mut(chunk)
|
||||
.zip(other.coeffs.chunks(chunk))
|
||||
{
|
||||
scope.spawn(move || {
|
||||
for (a, b) in a.iter_mut().zip(b.iter()) {
|
||||
a.group_mul_assign(&b.0);
|
||||
|
@ -174,7 +175,11 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
|
|||
assert_eq!(self.coeffs.len(), other.coeffs.len());
|
||||
|
||||
worker.scope(self.coeffs.len(), |scope, chunk| {
|
||||
for (a, b) in self.coeffs.chunks_mut(chunk).zip(other.coeffs.chunks(chunk)) {
|
||||
for (a, b) in self
|
||||
.coeffs
|
||||
.chunks_mut(chunk)
|
||||
.zip(other.coeffs.chunks(chunk))
|
||||
{
|
||||
scope.spawn(move || {
|
||||
for (a, b) in a.iter_mut().zip(b.iter()) {
|
||||
a.group_sub_assign(&b);
|
||||
|
@ -200,7 +205,7 @@ impl<G: CurveProjective> PartialEq for Point<G> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<G: CurveProjective> Copy for Point<G> { }
|
||||
impl<G: CurveProjective> Copy for Point<G> {}
|
||||
|
||||
impl<G: CurveProjective> Clone for Point<G> {
|
||||
fn clone(&self) -> Point<G> {
|
||||
|
@ -231,7 +236,7 @@ impl<E: ScalarEngine> PartialEq for Scalar<E> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<E: ScalarEngine> Copy for Scalar<E> { }
|
||||
impl<E: ScalarEngine> Copy for Scalar<E> {}
|
||||
|
||||
impl<E: ScalarEngine> Clone for Scalar<E> {
|
||||
fn clone(&self) -> Scalar<E> {
|
||||
|
@ -254,8 +259,7 @@ impl<E: ScalarEngine> Group<E> for Scalar<E> {
|
|||
}
|
||||
}
|
||||
|
||||
fn best_fft<E: ScalarEngine, T: Group<E>>(a: &mut [T], worker: &Worker, omega: &E::Fr, log_n: u32)
|
||||
{
|
||||
fn best_fft<E: ScalarEngine, T: Group<E>>(a: &mut [T], worker: &Worker, omega: &E::Fr, log_n: u32) {
|
||||
let log_cpus = worker.log_num_cpus();
|
||||
|
||||
if log_n <= log_cpus {
|
||||
|
@ -265,8 +269,7 @@ fn best_fft<E: ScalarEngine, T: Group<E>>(a: &mut [T], worker: &Worker, omega: &
|
|||
}
|
||||
}
|
||||
|
||||
fn serial_fft<E: ScalarEngine, T: Group<E>>(a: &mut [T], omega: &E::Fr, log_n: u32)
|
||||
{
|
||||
fn serial_fft<E: ScalarEngine, T: Group<E>>(a: &mut [T], omega: &E::Fr, log_n: u32) {
|
||||
fn bitreverse(mut n: u32, l: u32) -> u32 {
|
||||
let mut r = 0;
|
||||
for _ in 0..l {
|
||||
|
@ -288,22 +291,22 @@ fn serial_fft<E: ScalarEngine, T: Group<E>>(a: &mut [T], omega: &E::Fr, log_n: u
|
|||
|
||||
let mut m = 1;
|
||||
for _ in 0..log_n {
|
||||
let w_m = omega.pow(&[(n / (2*m)) as u64]);
|
||||
let w_m = omega.pow(&[(n / (2 * m)) as u64]);
|
||||
|
||||
let mut k = 0;
|
||||
while k < n {
|
||||
let mut w = E::Fr::one();
|
||||
for j in 0..m {
|
||||
let mut t = a[(k+j+m) as usize];
|
||||
let mut t = a[(k + j + m) as usize];
|
||||
t.group_mul_assign(&w);
|
||||
let mut tmp = a[(k+j) as usize];
|
||||
let mut tmp = a[(k + j) as usize];
|
||||
tmp.group_sub_assign(&t);
|
||||
a[(k+j+m) as usize] = tmp;
|
||||
a[(k+j) as usize].group_add_assign(&t);
|
||||
a[(k + j + m) as usize] = tmp;
|
||||
a[(k + j) as usize].group_add_assign(&t);
|
||||
w.mul_assign(&w_m);
|
||||
}
|
||||
|
||||
k += 2*m;
|
||||
k += 2 * m;
|
||||
}
|
||||
|
||||
m *= 2;
|
||||
|
@ -315,9 +318,8 @@ fn parallel_fft<E: ScalarEngine, T: Group<E>>(
|
|||
worker: &Worker,
|
||||
omega: &E::Fr,
|
||||
log_n: u32,
|
||||
log_cpus: u32
|
||||
)
|
||||
{
|
||||
log_cpus: u32,
|
||||
) {
|
||||
assert!(log_n >= log_cpus);
|
||||
|
||||
let num_cpus = 1 << log_cpus;
|
||||
|
@ -377,14 +379,17 @@ fn polynomial_arith() {
|
|||
use pairing::bls12_381::Bls12;
|
||||
use rand_core::RngCore;
|
||||
|
||||
fn test_mul<E: ScalarEngine, R: RngCore>(rng: &mut R)
|
||||
{
|
||||
fn test_mul<E: ScalarEngine, R: RngCore>(rng: &mut R) {
|
||||
let worker = Worker::new();
|
||||
|
||||
for coeffs_a in 0..70 {
|
||||
for coeffs_b in 0..70 {
|
||||
let mut a: Vec<_> = (0..coeffs_a).map(|_| Scalar::<E>(E::Fr::random(rng))).collect();
|
||||
let mut b: Vec<_> = (0..coeffs_b).map(|_| Scalar::<E>(E::Fr::random(rng))).collect();
|
||||
let mut a: Vec<_> = (0..coeffs_a)
|
||||
.map(|_| Scalar::<E>(E::Fr::random(rng)))
|
||||
.collect();
|
||||
let mut b: Vec<_> = (0..coeffs_b)
|
||||
.map(|_| Scalar::<E>(E::Fr::random(rng)))
|
||||
.collect();
|
||||
|
||||
// naive evaluation
|
||||
let mut naive = vec![Scalar(E::Fr::zero()); coeffs_a + coeffs_b];
|
||||
|
@ -425,8 +430,7 @@ fn fft_composition() {
|
|||
use pairing::bls12_381::Bls12;
|
||||
use rand_core::RngCore;
|
||||
|
||||
fn test_comp<E: ScalarEngine, R: RngCore>(rng: &mut R)
|
||||
{
|
||||
fn test_comp<E: ScalarEngine, R: RngCore>(rng: &mut R) {
|
||||
let worker = Worker::new();
|
||||
|
||||
for coeffs in 0..10 {
|
||||
|
@ -465,19 +469,20 @@ fn parallel_fft_consistency() {
|
|||
use rand_core::RngCore;
|
||||
use std::cmp::min;
|
||||
|
||||
fn test_consistency<E: ScalarEngine, R: RngCore>(rng: &mut R)
|
||||
{
|
||||
fn test_consistency<E: ScalarEngine, R: RngCore>(rng: &mut R) {
|
||||
let worker = Worker::new();
|
||||
|
||||
for _ in 0..5 {
|
||||
for log_d in 0..10 {
|
||||
let d = 1 << log_d;
|
||||
|
||||
let v1 = (0..d).map(|_| Scalar::<E>(E::Fr::random(rng))).collect::<Vec<_>>();
|
||||
let v1 = (0..d)
|
||||
.map(|_| Scalar::<E>(E::Fr::random(rng)))
|
||||
.collect::<Vec<_>>();
|
||||
let mut v1 = EvaluationDomain::from_coeffs(v1).unwrap();
|
||||
let mut v2 = EvaluationDomain::from_coeffs(v1.coeffs.clone()).unwrap();
|
||||
|
||||
for log_cpus in log_d..min(log_d+1, 3) {
|
||||
for log_cpus in log_d..min(log_d + 1, 3) {
|
||||
parallel_fft(&mut v1.coeffs, &worker, &v1.omega, log_d, log_cpus);
|
||||
serial_fft(&mut v2.coeffs, &v2.omega, log_d);
|
||||
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
pub mod test;
|
||||
|
||||
pub mod boolean;
|
||||
pub mod multieq;
|
||||
pub mod uint32;
|
||||
pub mod blake2s;
|
||||
pub mod num;
|
||||
pub mod boolean;
|
||||
pub mod lookup;
|
||||
pub mod multieq;
|
||||
pub mod multipack;
|
||||
pub mod num;
|
||||
pub mod sha256;
|
||||
pub mod uint32;
|
||||
|
||||
use crate::{
|
||||
SynthesisError
|
||||
};
|
||||
use crate::SynthesisError;
|
||||
|
||||
// TODO: This should probably be removed and we
|
||||
// should use existing helper methods on `Option`
|
||||
|
@ -27,7 +25,7 @@ impl<T> Assignment<T> for Option<T> {
|
|||
fn get(&self) -> Result<&T, SynthesisError> {
|
||||
match *self {
|
||||
Some(ref v) => Ok(v),
|
||||
None => Err(SynthesisError::AssignmentMissing)
|
||||
None => Err(SynthesisError::AssignmentMissing),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,10 @@
|
|||
use pairing::{
|
||||
Engine,
|
||||
};
|
||||
use pairing::Engine;
|
||||
|
||||
use crate::{
|
||||
SynthesisError,
|
||||
ConstraintSystem
|
||||
};
|
||||
use crate::{ConstraintSystem, SynthesisError};
|
||||
|
||||
use super::boolean::{
|
||||
Boolean
|
||||
};
|
||||
use super::boolean::Boolean;
|
||||
|
||||
use super::uint32::{
|
||||
UInt32
|
||||
};
|
||||
use super::uint32::UInt32;
|
||||
|
||||
use super::multieq::MultiEq;
|
||||
|
||||
|
@ -65,7 +56,7 @@ const SIGMA: [[usize; 16]; 10] = [
|
|||
[12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
|
||||
[13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
|
||||
[6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
|
||||
[10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0]
|
||||
[10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
|
||||
];
|
||||
|
||||
/*
|
||||
|
@ -98,17 +89,30 @@ fn mixing_g<E: Engine, CS: ConstraintSystem<E>, M>(
|
|||
c: usize,
|
||||
d: usize,
|
||||
x: &UInt32,
|
||||
y: &UInt32
|
||||
y: &UInt32,
|
||||
) -> Result<(), SynthesisError>
|
||||
where M: ConstraintSystem<E, Root=MultiEq<E, CS>>
|
||||
where
|
||||
M: ConstraintSystem<E, Root = MultiEq<E, CS>>,
|
||||
{
|
||||
v[a] = UInt32::addmany(cs.namespace(|| "mixing step 1"), &[v[a].clone(), v[b].clone(), x.clone()])?;
|
||||
v[a] = UInt32::addmany(
|
||||
cs.namespace(|| "mixing step 1"),
|
||||
&[v[a].clone(), v[b].clone(), x.clone()],
|
||||
)?;
|
||||
v[d] = v[d].xor(cs.namespace(|| "mixing step 2"), &v[a])?.rotr(R1);
|
||||
v[c] = UInt32::addmany(cs.namespace(|| "mixing step 3"), &[v[c].clone(), v[d].clone()])?;
|
||||
v[c] = UInt32::addmany(
|
||||
cs.namespace(|| "mixing step 3"),
|
||||
&[v[c].clone(), v[d].clone()],
|
||||
)?;
|
||||
v[b] = v[b].xor(cs.namespace(|| "mixing step 4"), &v[c])?.rotr(R2);
|
||||
v[a] = UInt32::addmany(cs.namespace(|| "mixing step 5"), &[v[a].clone(), v[b].clone(), y.clone()])?;
|
||||
v[a] = UInt32::addmany(
|
||||
cs.namespace(|| "mixing step 5"),
|
||||
&[v[a].clone(), v[b].clone(), y.clone()],
|
||||
)?;
|
||||
v[d] = v[d].xor(cs.namespace(|| "mixing step 6"), &v[a])?.rotr(R3);
|
||||
v[c] = UInt32::addmany(cs.namespace(|| "mixing step 7"), &[v[c].clone(), v[d].clone()])?;
|
||||
v[c] = UInt32::addmany(
|
||||
cs.namespace(|| "mixing step 7"),
|
||||
&[v[c].clone(), v[d].clone()],
|
||||
)?;
|
||||
v[b] = v[b].xor(cs.namespace(|| "mixing step 8"), &v[c])?.rotr(R4);
|
||||
|
||||
Ok(())
|
||||
|
@ -162,15 +166,13 @@ fn mixing_g<E: Engine, CS: ConstraintSystem<E>, M>(
|
|||
END FUNCTION.
|
||||
*/
|
||||
|
||||
|
||||
fn blake2s_compression<E: Engine, CS: ConstraintSystem<E>>(
|
||||
mut cs: CS,
|
||||
h: &mut [UInt32],
|
||||
m: &[UInt32],
|
||||
t: u64,
|
||||
f: bool
|
||||
) -> Result<(), SynthesisError>
|
||||
{
|
||||
f: bool,
|
||||
) -> Result<(), SynthesisError> {
|
||||
assert_eq!(h.len(), 8);
|
||||
assert_eq!(m.len(), 16);
|
||||
|
||||
|
@ -196,10 +198,16 @@ fn blake2s_compression<E: Engine, CS: ConstraintSystem<E>>(
|
|||
assert_eq!(v.len(), 16);
|
||||
|
||||
v[12] = v[12].xor(cs.namespace(|| "first xor"), &UInt32::constant(t as u32))?;
|
||||
v[13] = v[13].xor(cs.namespace(|| "second xor"), &UInt32::constant((t >> 32) as u32))?;
|
||||
v[13] = v[13].xor(
|
||||
cs.namespace(|| "second xor"),
|
||||
&UInt32::constant((t >> 32) as u32),
|
||||
)?;
|
||||
|
||||
if f {
|
||||
v[14] = v[14].xor(cs.namespace(|| "third xor"), &UInt32::constant(u32::max_value()))?;
|
||||
v[14] = v[14].xor(
|
||||
cs.namespace(|| "third xor"),
|
||||
&UInt32::constant(u32::max_value()),
|
||||
)?;
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -210,20 +218,92 @@ fn blake2s_compression<E: Engine, CS: ConstraintSystem<E>>(
|
|||
|
||||
let s = SIGMA[i % 10];
|
||||
|
||||
mixing_g(cs.namespace(|| "mixing invocation 1"), &mut v, 0, 4, 8, 12, &m[s[ 0]], &m[s[ 1]])?;
|
||||
mixing_g(cs.namespace(|| "mixing invocation 2"), &mut v, 1, 5, 9, 13, &m[s[ 2]], &m[s[ 3]])?;
|
||||
mixing_g(cs.namespace(|| "mixing invocation 3"), &mut v, 2, 6, 10, 14, &m[s[ 4]], &m[s[ 5]])?;
|
||||
mixing_g(cs.namespace(|| "mixing invocation 4"), &mut v, 3, 7, 11, 15, &m[s[ 6]], &m[s[ 7]])?;
|
||||
mixing_g(
|
||||
cs.namespace(|| "mixing invocation 1"),
|
||||
&mut v,
|
||||
0,
|
||||
4,
|
||||
8,
|
||||
12,
|
||||
&m[s[0]],
|
||||
&m[s[1]],
|
||||
)?;
|
||||
mixing_g(
|
||||
cs.namespace(|| "mixing invocation 2"),
|
||||
&mut v,
|
||||
1,
|
||||
5,
|
||||
9,
|
||||
13,
|
||||
&m[s[2]],
|
||||
&m[s[3]],
|
||||
)?;
|
||||
mixing_g(
|
||||
cs.namespace(|| "mixing invocation 3"),
|
||||
&mut v,
|
||||
2,
|
||||
6,
|
||||
10,
|
||||
14,
|
||||
&m[s[4]],
|
||||
&m[s[5]],
|
||||
)?;
|
||||
mixing_g(
|
||||
cs.namespace(|| "mixing invocation 4"),
|
||||
&mut v,
|
||||
3,
|
||||
7,
|
||||
11,
|
||||
15,
|
||||
&m[s[6]],
|
||||
&m[s[7]],
|
||||
)?;
|
||||
|
||||
mixing_g(cs.namespace(|| "mixing invocation 5"), &mut v, 0, 5, 10, 15, &m[s[ 8]], &m[s[ 9]])?;
|
||||
mixing_g(cs.namespace(|| "mixing invocation 6"), &mut v, 1, 6, 11, 12, &m[s[10]], &m[s[11]])?;
|
||||
mixing_g(cs.namespace(|| "mixing invocation 7"), &mut v, 2, 7, 8, 13, &m[s[12]], &m[s[13]])?;
|
||||
mixing_g(cs.namespace(|| "mixing invocation 8"), &mut v, 3, 4, 9, 14, &m[s[14]], &m[s[15]])?;
|
||||
mixing_g(
|
||||
cs.namespace(|| "mixing invocation 5"),
|
||||
&mut v,
|
||||
0,
|
||||
5,
|
||||
10,
|
||||
15,
|
||||
&m[s[8]],
|
||||
&m[s[9]],
|
||||
)?;
|
||||
mixing_g(
|
||||
cs.namespace(|| "mixing invocation 6"),
|
||||
&mut v,
|
||||
1,
|
||||
6,
|
||||
11,
|
||||
12,
|
||||
&m[s[10]],
|
||||
&m[s[11]],
|
||||
)?;
|
||||
mixing_g(
|
||||
cs.namespace(|| "mixing invocation 7"),
|
||||
&mut v,
|
||||
2,
|
||||
7,
|
||||
8,
|
||||
13,
|
||||
&m[s[12]],
|
||||
&m[s[13]],
|
||||
)?;
|
||||
mixing_g(
|
||||
cs.namespace(|| "mixing invocation 8"),
|
||||
&mut v,
|
||||
3,
|
||||
4,
|
||||
9,
|
||||
14,
|
||||
&m[s[14]],
|
||||
&m[s[15]],
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
for i in 0..8 {
|
||||
let mut cs = cs.namespace(|| format!("h[{i}] ^ v[{i}] ^ v[{i} + 8]", i=i));
|
||||
let mut cs = cs.namespace(|| format!("h[{i}] ^ v[{i}] ^ v[{i} + 8]", i = i));
|
||||
|
||||
h[i] = h[i].xor(cs.namespace(|| "first xor"), &v[i])?;
|
||||
h[i] = h[i].xor(cs.namespace(|| "second xor"), &v[i + 8])?;
|
||||
|
@ -262,9 +342,8 @@ fn blake2s_compression<E: Engine, CS: ConstraintSystem<E>>(
|
|||
pub fn blake2s<E: Engine, CS: ConstraintSystem<E>>(
|
||||
mut cs: CS,
|
||||
input: &[Boolean],
|
||||
personalization: &[u8]
|
||||
) -> Result<Vec<Boolean>, SynthesisError>
|
||||
{
|
||||
personalization: &[u8],
|
||||
) -> Result<Vec<Boolean>, SynthesisError> {
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
assert_eq!(personalization.len(), 8);
|
||||
|
@ -279,8 +358,12 @@ pub fn blake2s<E: Engine, CS: ConstraintSystem<E>>(
|
|||
h.push(UInt32::constant(0x9B05688C));
|
||||
|
||||
// Personalization is stored here
|
||||
h.push(UInt32::constant(0x1F83D9AB ^ LittleEndian::read_u32(&personalization[0..4])));
|
||||
h.push(UInt32::constant(0x5BE0CD19 ^ LittleEndian::read_u32(&personalization[4..8])));
|
||||
h.push(UInt32::constant(
|
||||
0x1F83D9AB ^ LittleEndian::read_u32(&personalization[0..4]),
|
||||
));
|
||||
h.push(UInt32::constant(
|
||||
0x5BE0CD19 ^ LittleEndian::read_u32(&personalization[4..8]),
|
||||
));
|
||||
|
||||
let mut blocks: Vec<Vec<UInt32>> = vec![];
|
||||
|
||||
|
@ -312,7 +395,13 @@ pub fn blake2s<E: Engine, CS: ConstraintSystem<E>>(
|
|||
{
|
||||
let cs = cs.namespace(|| "final block");
|
||||
|
||||
blake2s_compression(cs, &mut h, &blocks[blocks.len() - 1], (input.len() / 8) as u64, true)?;
|
||||
blake2s_compression(
|
||||
cs,
|
||||
&mut h,
|
||||
&blocks[blocks.len() - 1],
|
||||
(input.len() / 8) as u64,
|
||||
true,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(h.iter().flat_map(|b| b.into_bits()).collect())
|
||||
|
@ -321,14 +410,14 @@ pub fn blake2s<E: Engine, CS: ConstraintSystem<E>>(
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use blake2s_simd::Params as Blake2sParams;
|
||||
use pairing::bls12_381::{Bls12};
|
||||
use pairing::bls12_381::Bls12;
|
||||
use rand_core::{RngCore, SeedableRng};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
|
||||
use crate::gadgets::boolean::{Boolean, AllocatedBit};
|
||||
use crate::gadgets::test::TestConstraintSystem;
|
||||
use super::blake2s;
|
||||
use crate::{ConstraintSystem};
|
||||
use crate::gadgets::boolean::{AllocatedBit, Boolean};
|
||||
use crate::gadgets::test::TestConstraintSystem;
|
||||
use crate::ConstraintSystem;
|
||||
|
||||
#[test]
|
||||
fn test_blank_hash() {
|
||||
|
@ -356,7 +445,13 @@ mod test {
|
|||
#[test]
|
||||
fn test_blake2s_constraints() {
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
let input_bits: Vec<_> = (0..512).map(|i| AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)).unwrap().into()).collect();
|
||||
let input_bits: Vec<_> = (0..512)
|
||||
.map(|i| {
|
||||
AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true))
|
||||
.unwrap()
|
||||
.into()
|
||||
})
|
||||
.collect();
|
||||
blake2s(&mut cs, &input_bits, b"12345678").unwrap();
|
||||
assert!(cs.is_satisfied());
|
||||
assert_eq!(cs.num_constraints(), 21518);
|
||||
|
@ -369,14 +464,17 @@ mod test {
|
|||
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
let input_bits: Vec<_> = (0..512)
|
||||
.map(|_| Boolean::constant(rng.next_u32() % 2 != 0))
|
||||
.chain((0..512)
|
||||
.map(|i| AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)).unwrap().into()))
|
||||
.collect();
|
||||
.map(|_| Boolean::constant(rng.next_u32() % 2 != 0))
|
||||
.chain((0..512).map(|i| {
|
||||
AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true))
|
||||
.unwrap()
|
||||
.into()
|
||||
}))
|
||||
.collect();
|
||||
blake2s(&mut cs, &input_bits, b"12345678").unwrap();
|
||||
assert!(cs.is_satisfied());
|
||||
assert_eq!(cs.num_constraints(), 21518);
|
||||
|
@ -386,10 +484,12 @@ mod test {
|
|||
fn test_blake2s_constant_constraints() {
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
let input_bits: Vec<_> = (0..512).map(|_| Boolean::constant(rng.next_u32() % 2 != 0)).collect();
|
||||
let input_bits: Vec<_> = (0..512)
|
||||
.map(|_| Boolean::constant(rng.next_u32() % 2 != 0))
|
||||
.collect();
|
||||
blake2s(&mut cs, &input_bits, b"12345678").unwrap();
|
||||
assert_eq!(cs.num_constraints(), 0);
|
||||
}
|
||||
|
@ -397,13 +497,15 @@ mod test {
|
|||
#[test]
|
||||
fn test_blake2s() {
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0))
|
||||
{
|
||||
let mut h = Blake2sParams::new().hash_length(32).personal(b"12345678").to_state();
|
||||
for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) {
|
||||
let mut h = Blake2sParams::new()
|
||||
.hash_length(32)
|
||||
.personal(b"12345678")
|
||||
.to_state();
|
||||
|
||||
let data: Vec<u8> = (0..input_len).map(|_| rng.next_u32() as u8).collect();
|
||||
|
||||
|
@ -419,7 +521,11 @@ mod test {
|
|||
for bit_i in 0..8 {
|
||||
let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i));
|
||||
|
||||
input_bits.push(AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)).unwrap().into());
|
||||
input_bits.push(
|
||||
AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8))
|
||||
.unwrap()
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -427,17 +533,19 @@ mod test {
|
|||
|
||||
assert!(cs.is_satisfied());
|
||||
|
||||
let mut s = hash_result.as_ref().iter()
|
||||
.flat_map(|&byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8));
|
||||
let mut s = hash_result
|
||||
.as_ref()
|
||||
.iter()
|
||||
.flat_map(|&byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8));
|
||||
|
||||
for b in r {
|
||||
match b {
|
||||
Boolean::Is(b) => {
|
||||
assert!(s.next().unwrap() == b.get_value().unwrap());
|
||||
},
|
||||
}
|
||||
Boolean::Not(b) => {
|
||||
assert!(s.next().unwrap() != b.get_value().unwrap());
|
||||
},
|
||||
}
|
||||
Boolean::Constant(b) => {
|
||||
assert!(input_len == 0);
|
||||
assert!(s.next().unwrap() == b);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,23 +1,15 @@
|
|||
use ff::Field;
|
||||
use pairing::Engine;
|
||||
|
||||
use super::*;
|
||||
use super::num::{
|
||||
AllocatedNum,
|
||||
Num
|
||||
};
|
||||
use super::boolean::Boolean;
|
||||
use crate::{
|
||||
ConstraintSystem
|
||||
};
|
||||
use super::num::{AllocatedNum, Num};
|
||||
use super::*;
|
||||
use crate::ConstraintSystem;
|
||||
|
||||
// Synthesize the constants for each base pattern.
|
||||
fn synth<'a, E: Engine, I>(
|
||||
window_size: usize,
|
||||
constants: I,
|
||||
assignment: &mut [E::Fr]
|
||||
)
|
||||
where I: IntoIterator<Item=&'a E::Fr>
|
||||
fn synth<'a, E: Engine, I>(window_size: usize, constants: I, assignment: &mut [E::Fr])
|
||||
where
|
||||
I: IntoIterator<Item = &'a E::Fr>,
|
||||
{
|
||||
assert_eq!(assignment.len(), 1 << window_size);
|
||||
|
||||
|
@ -39,16 +31,20 @@ fn synth<'a, E: Engine, I>(
|
|||
pub fn lookup3_xy<E: Engine, CS>(
|
||||
mut cs: CS,
|
||||
bits: &[Boolean],
|
||||
coords: &[(E::Fr, E::Fr)]
|
||||
coords: &[(E::Fr, E::Fr)],
|
||||
) -> Result<(AllocatedNum<E>, AllocatedNum<E>), SynthesisError>
|
||||
where CS: ConstraintSystem<E>
|
||||
where
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
assert_eq!(bits.len(), 3);
|
||||
assert_eq!(coords.len(), 8);
|
||||
|
||||
// Calculate the index into `coords`
|
||||
let i =
|
||||
match (bits[0].get_value(), bits[1].get_value(), bits[2].get_value()) {
|
||||
let i = match (
|
||||
bits[0].get_value(),
|
||||
bits[1].get_value(),
|
||||
bits[2].get_value(),
|
||||
) {
|
||||
(Some(a_value), Some(b_value), Some(c_value)) => {
|
||||
let mut tmp = 0;
|
||||
if a_value {
|
||||
|
@ -61,25 +57,15 @@ pub fn lookup3_xy<E: Engine, CS>(
|
|||
tmp += 4;
|
||||
}
|
||||
Some(tmp)
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
// Allocate the x-coordinate resulting from the lookup
|
||||
let res_x = AllocatedNum::alloc(
|
||||
cs.namespace(|| "x"),
|
||||
|| {
|
||||
Ok(coords[*i.get()?].0)
|
||||
}
|
||||
)?;
|
||||
let res_x = AllocatedNum::alloc(cs.namespace(|| "x"), || Ok(coords[*i.get()?].0))?;
|
||||
|
||||
// Allocate the y-coordinate resulting from the lookup
|
||||
let res_y = AllocatedNum::alloc(
|
||||
cs.namespace(|| "y"),
|
||||
|| {
|
||||
Ok(coords[*i.get()?].1)
|
||||
}
|
||||
)?;
|
||||
let res_y = AllocatedNum::alloc(cs.namespace(|| "y"), || Ok(coords[*i.get()?].1))?;
|
||||
|
||||
// Compute the coefficients for the lookup constraints
|
||||
let mut x_coeffs = [E::Fr::zero(); 8];
|
||||
|
@ -93,30 +79,38 @@ pub fn lookup3_xy<E: Engine, CS>(
|
|||
|
||||
cs.enforce(
|
||||
|| "x-coordinate lookup",
|
||||
|lc| lc + (x_coeffs[0b001], one)
|
||||
|lc| {
|
||||
lc + (x_coeffs[0b001], one)
|
||||
+ &bits[1].lc::<E>(one, x_coeffs[0b011])
|
||||
+ &bits[2].lc::<E>(one, x_coeffs[0b101])
|
||||
+ &precomp.lc::<E>(one, x_coeffs[0b111]),
|
||||
+ &precomp.lc::<E>(one, x_coeffs[0b111])
|
||||
},
|
||||
|lc| lc + &bits[0].lc::<E>(one, E::Fr::one()),
|
||||
|lc| lc + res_x.get_variable()
|
||||
|lc| {
|
||||
lc + res_x.get_variable()
|
||||
- (x_coeffs[0b000], one)
|
||||
- &bits[1].lc::<E>(one, x_coeffs[0b010])
|
||||
- &bits[2].lc::<E>(one, x_coeffs[0b100])
|
||||
- &precomp.lc::<E>(one, x_coeffs[0b110]),
|
||||
- &precomp.lc::<E>(one, x_coeffs[0b110])
|
||||
},
|
||||
);
|
||||
|
||||
cs.enforce(
|
||||
|| "y-coordinate lookup",
|
||||
|lc| lc + (y_coeffs[0b001], one)
|
||||
|lc| {
|
||||
lc + (y_coeffs[0b001], one)
|
||||
+ &bits[1].lc::<E>(one, y_coeffs[0b011])
|
||||
+ &bits[2].lc::<E>(one, y_coeffs[0b101])
|
||||
+ &precomp.lc::<E>(one, y_coeffs[0b111]),
|
||||
+ &precomp.lc::<E>(one, y_coeffs[0b111])
|
||||
},
|
||||
|lc| lc + &bits[0].lc::<E>(one, E::Fr::one()),
|
||||
|lc| lc + res_y.get_variable()
|
||||
|lc| {
|
||||
lc + res_y.get_variable()
|
||||
- (y_coeffs[0b000], one)
|
||||
- &bits[1].lc::<E>(one, y_coeffs[0b010])
|
||||
- &bits[2].lc::<E>(one, y_coeffs[0b100])
|
||||
- &precomp.lc::<E>(one, y_coeffs[0b110]),
|
||||
- &precomp.lc::<E>(one, y_coeffs[0b110])
|
||||
},
|
||||
);
|
||||
|
||||
Ok((res_x, res_y))
|
||||
|
@ -127,16 +121,16 @@ pub fn lookup3_xy<E: Engine, CS>(
|
|||
pub fn lookup3_xy_with_conditional_negation<E: Engine, CS>(
|
||||
mut cs: CS,
|
||||
bits: &[Boolean],
|
||||
coords: &[(E::Fr, E::Fr)]
|
||||
coords: &[(E::Fr, E::Fr)],
|
||||
) -> Result<(Num<E>, Num<E>), SynthesisError>
|
||||
where CS: ConstraintSystem<E>
|
||||
where
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
assert_eq!(bits.len(), 3);
|
||||
assert_eq!(coords.len(), 4);
|
||||
|
||||
// Calculate the index into `coords`
|
||||
let i =
|
||||
match (bits[0].get_value(), bits[1].get_value()) {
|
||||
let i = match (bits[0].get_value(), bits[1].get_value()) {
|
||||
(Some(a_value), Some(b_value)) => {
|
||||
let mut tmp = 0;
|
||||
if a_value {
|
||||
|
@ -146,22 +140,19 @@ pub fn lookup3_xy_with_conditional_negation<E: Engine, CS>(
|
|||
tmp += 2;
|
||||
}
|
||||
Some(tmp)
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
// Allocate the y-coordinate resulting from the lookup
|
||||
// and conditional negation
|
||||
let y = AllocatedNum::alloc(
|
||||
cs.namespace(|| "y"),
|
||||
|| {
|
||||
let mut tmp = coords[*i.get()?].1;
|
||||
if *bits[2].get_value().get()? {
|
||||
tmp.negate();
|
||||
}
|
||||
Ok(tmp)
|
||||
let y = AllocatedNum::alloc(cs.namespace(|| "y"), || {
|
||||
let mut tmp = coords[*i.get()?].1;
|
||||
if *bits[2].get_value().get()? {
|
||||
tmp.negate();
|
||||
}
|
||||
)?;
|
||||
Ok(tmp)
|
||||
})?;
|
||||
|
||||
let one = CS::one();
|
||||
|
||||
|
@ -174,21 +165,21 @@ pub fn lookup3_xy_with_conditional_negation<E: Engine, CS>(
|
|||
let precomp = Boolean::and(cs.namespace(|| "precomp"), &bits[0], &bits[1])?;
|
||||
|
||||
let x = Num::zero()
|
||||
.add_bool_with_coeff(one, &Boolean::constant(true), x_coeffs[0b00])
|
||||
.add_bool_with_coeff(one, &bits[0], x_coeffs[0b01])
|
||||
.add_bool_with_coeff(one, &bits[1], x_coeffs[0b10])
|
||||
.add_bool_with_coeff(one, &precomp, x_coeffs[0b11]);
|
||||
.add_bool_with_coeff(one, &Boolean::constant(true), x_coeffs[0b00])
|
||||
.add_bool_with_coeff(one, &bits[0], x_coeffs[0b01])
|
||||
.add_bool_with_coeff(one, &bits[1], x_coeffs[0b10])
|
||||
.add_bool_with_coeff(one, &precomp, x_coeffs[0b11]);
|
||||
|
||||
let y_lc = precomp.lc::<E>(one, y_coeffs[0b11]) +
|
||||
&bits[1].lc::<E>(one, y_coeffs[0b10]) +
|
||||
&bits[0].lc::<E>(one, y_coeffs[0b01]) +
|
||||
(y_coeffs[0b00], one);
|
||||
let y_lc = precomp.lc::<E>(one, y_coeffs[0b11])
|
||||
+ &bits[1].lc::<E>(one, y_coeffs[0b10])
|
||||
+ &bits[0].lc::<E>(one, y_coeffs[0b01])
|
||||
+ (y_coeffs[0b00], one);
|
||||
|
||||
cs.enforce(
|
||||
|| "y-coordinate lookup",
|
||||
|lc| lc + &y_lc + &y_lc,
|
||||
|lc| lc + &bits[2].lc::<E>(one, E::Fr::one()),
|
||||
|lc| lc + &y_lc - y.get_variable()
|
||||
|lc| lc + &y_lc - y.get_variable(),
|
||||
);
|
||||
|
||||
Ok((x, y.into()))
|
||||
|
@ -197,8 +188,8 @@ pub fn lookup3_xy_with_conditional_negation<E: Engine, CS>(
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::gadgets::boolean::{AllocatedBit, Boolean};
|
||||
use crate::gadgets::test::*;
|
||||
use crate::gadgets::boolean::{Boolean, AllocatedBit};
|
||||
use pairing::bls12_381::{Bls12, Fr};
|
||||
use rand_core::{RngCore, SeedableRng};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
|
@ -206,40 +197,42 @@ mod test {
|
|||
#[test]
|
||||
fn test_lookup3_xy() {
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for _ in 0..100 {
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let a_val = rng.next_u32() % 2 != 0;
|
||||
let a = Boolean::from(
|
||||
AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap()
|
||||
);
|
||||
let a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap());
|
||||
|
||||
let b_val = rng.next_u32() % 2 != 0;
|
||||
let b = Boolean::from(
|
||||
AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap()
|
||||
);
|
||||
let b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap());
|
||||
|
||||
let c_val = rng.next_u32() % 2 != 0;
|
||||
let c = Boolean::from(
|
||||
AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap()
|
||||
);
|
||||
let c = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap());
|
||||
|
||||
let bits = vec![a, b, c];
|
||||
|
||||
let points: Vec<(Fr, Fr)> = (0..8).map(|_| (Fr::random(&mut rng), Fr::random(&mut rng))).collect();
|
||||
let points: Vec<(Fr, Fr)> = (0..8)
|
||||
.map(|_| (Fr::random(&mut rng), Fr::random(&mut rng)))
|
||||
.collect();
|
||||
|
||||
let res = lookup3_xy(&mut cs, &bits, &points).unwrap();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
|
||||
let mut index = 0;
|
||||
if a_val { index += 1 }
|
||||
if b_val { index += 2 }
|
||||
if c_val { index += 4 }
|
||||
if a_val {
|
||||
index += 1
|
||||
}
|
||||
if b_val {
|
||||
index += 2
|
||||
}
|
||||
if c_val {
|
||||
index += 4
|
||||
}
|
||||
|
||||
assert_eq!(res.0.get_value().unwrap(), points[index].0);
|
||||
assert_eq!(res.1.get_value().unwrap(), points[index].1);
|
||||
|
@ -249,43 +242,45 @@ mod test {
|
|||
#[test]
|
||||
fn test_lookup3_xy_with_conditional_negation() {
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for _ in 0..100 {
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let a_val = rng.next_u32() % 2 != 0;
|
||||
let a = Boolean::from(
|
||||
AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap()
|
||||
);
|
||||
let a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap());
|
||||
|
||||
let b_val = rng.next_u32() % 2 != 0;
|
||||
let b = Boolean::from(
|
||||
AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap()
|
||||
);
|
||||
let b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap());
|
||||
|
||||
let c_val = rng.next_u32() % 2 != 0;
|
||||
let c = Boolean::from(
|
||||
AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap()
|
||||
);
|
||||
let c = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap());
|
||||
|
||||
let bits = vec![a, b, c];
|
||||
|
||||
let points: Vec<(Fr, Fr)> = (0..4).map(|_| (Fr::random(&mut rng), Fr::random(&mut rng))).collect();
|
||||
let points: Vec<(Fr, Fr)> = (0..4)
|
||||
.map(|_| (Fr::random(&mut rng), Fr::random(&mut rng)))
|
||||
.collect();
|
||||
|
||||
let res = lookup3_xy_with_conditional_negation(&mut cs, &bits, &points).unwrap();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
|
||||
let mut index = 0;
|
||||
if a_val { index += 1 }
|
||||
if b_val { index += 2 }
|
||||
if a_val {
|
||||
index += 1
|
||||
}
|
||||
if b_val {
|
||||
index += 2
|
||||
}
|
||||
|
||||
assert_eq!(res.0.get_value().unwrap(), points[index].0);
|
||||
let mut tmp = points[index].1;
|
||||
if c_val { tmp.negate() }
|
||||
if c_val {
|
||||
tmp.negate()
|
||||
}
|
||||
assert_eq!(res.1.get_value().unwrap(), tmp);
|
||||
}
|
||||
}
|
||||
|
@ -293,14 +288,16 @@ mod test {
|
|||
#[test]
|
||||
fn test_synth() {
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
let window_size = 4;
|
||||
|
||||
let mut assignment = vec![Fr::zero(); 1 << window_size];
|
||||
let constants: Vec<_> = (0..(1 << window_size)).map(|_| Fr::random(&mut rng)).collect();
|
||||
let constants: Vec<_> = (0..(1 << window_size))
|
||||
.map(|_| Fr::random(&mut rng))
|
||||
.collect();
|
||||
|
||||
synth::<Bls12, _>(window_size, &constants, &mut assignment);
|
||||
|
||||
|
|
|
@ -1,14 +1,9 @@
|
|||
use ff::{Field, PrimeField};
|
||||
use pairing::Engine;
|
||||
|
||||
use crate::{
|
||||
SynthesisError,
|
||||
ConstraintSystem,
|
||||
LinearCombination,
|
||||
Variable
|
||||
};
|
||||
use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable};
|
||||
|
||||
pub struct MultiEq<E: Engine, CS: ConstraintSystem<E>>{
|
||||
pub struct MultiEq<E: Engine, CS: ConstraintSystem<E>> {
|
||||
cs: CS,
|
||||
ops: usize,
|
||||
bits_used: usize,
|
||||
|
@ -23,12 +18,11 @@ impl<E: Engine, CS: ConstraintSystem<E>> MultiEq<E, CS> {
|
|||
ops: 0,
|
||||
bits_used: 0,
|
||||
lhs: LinearCombination::zero(),
|
||||
rhs: LinearCombination::zero()
|
||||
rhs: LinearCombination::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
fn accumulate(&mut self)
|
||||
{
|
||||
fn accumulate(&mut self) {
|
||||
let ops = self.ops;
|
||||
let lhs = self.lhs.clone();
|
||||
let rhs = self.rhs.clone();
|
||||
|
@ -36,7 +30,7 @@ impl<E: Engine, CS: ConstraintSystem<E>> MultiEq<E, CS> {
|
|||
|| format!("multieq {}", ops),
|
||||
|_| lhs,
|
||||
|lc| lc + CS::one(),
|
||||
|_| rhs
|
||||
|_| rhs,
|
||||
);
|
||||
self.lhs = LinearCombination::zero();
|
||||
self.rhs = LinearCombination::zero();
|
||||
|
@ -48,9 +42,8 @@ impl<E: Engine, CS: ConstraintSystem<E>> MultiEq<E, CS> {
|
|||
&mut self,
|
||||
num_bits: usize,
|
||||
lhs: &LinearCombination<E>,
|
||||
rhs: &LinearCombination<E>
|
||||
)
|
||||
{
|
||||
rhs: &LinearCombination<E>,
|
||||
) {
|
||||
// Check if we will exceed the capacity
|
||||
if (E::Fr::CAPACITY as usize) <= (self.bits_used + num_bits) {
|
||||
self.accumulate();
|
||||
|
@ -68,67 +61,60 @@ impl<E: Engine, CS: ConstraintSystem<E>> MultiEq<E, CS> {
|
|||
impl<E: Engine, CS: ConstraintSystem<E>> Drop for MultiEq<E, CS> {
|
||||
fn drop(&mut self) {
|
||||
if self.bits_used > 0 {
|
||||
self.accumulate();
|
||||
self.accumulate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine, CS: ConstraintSystem<E>> ConstraintSystem<E> for MultiEq<E, CS>
|
||||
{
|
||||
impl<E: Engine, CS: ConstraintSystem<E>> ConstraintSystem<E> for MultiEq<E, CS> {
|
||||
type Root = Self;
|
||||
|
||||
fn one() -> Variable {
|
||||
CS::one()
|
||||
}
|
||||
|
||||
fn alloc<F, A, AR>(
|
||||
&mut self,
|
||||
annotation: A,
|
||||
f: F
|
||||
) -> Result<Variable, SynthesisError>
|
||||
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
|
||||
fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
|
||||
where
|
||||
F: FnOnce() -> Result<E::Fr, SynthesisError>,
|
||||
A: FnOnce() -> AR,
|
||||
AR: Into<String>,
|
||||
{
|
||||
self.cs.alloc(annotation, f)
|
||||
}
|
||||
|
||||
fn alloc_input<F, A, AR>(
|
||||
&mut self,
|
||||
annotation: A,
|
||||
f: F
|
||||
) -> Result<Variable, SynthesisError>
|
||||
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
|
||||
fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
|
||||
where
|
||||
F: FnOnce() -> Result<E::Fr, SynthesisError>,
|
||||
A: FnOnce() -> AR,
|
||||
AR: Into<String>,
|
||||
{
|
||||
self.cs.alloc_input(annotation, f)
|
||||
}
|
||||
|
||||
fn enforce<A, AR, LA, LB, LC>(
|
||||
&mut self,
|
||||
annotation: 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>
|
||||
fn enforce<A, AR, LA, LB, LC>(&mut self, annotation: 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>,
|
||||
{
|
||||
self.cs.enforce(annotation, a, b, c)
|
||||
}
|
||||
|
||||
fn push_namespace<NR, N>(&mut self, name_fn: N)
|
||||
where NR: Into<String>, N: FnOnce() -> NR
|
||||
where
|
||||
NR: Into<String>,
|
||||
N: FnOnce() -> NR,
|
||||
{
|
||||
self.cs.get_root().push_namespace(name_fn)
|
||||
}
|
||||
|
||||
fn pop_namespace(&mut self)
|
||||
{
|
||||
fn pop_namespace(&mut self) {
|
||||
self.cs.get_root().pop_namespace()
|
||||
}
|
||||
|
||||
fn get_root(&mut self) -> &mut Self::Root
|
||||
{
|
||||
fn get_root(&mut self) -> &mut Self::Root {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,18 @@
|
|||
use ff::{Field, PrimeField};
|
||||
use pairing::Engine;
|
||||
use crate::{ConstraintSystem, SynthesisError};
|
||||
use super::boolean::{Boolean};
|
||||
use super::boolean::Boolean;
|
||||
use super::num::Num;
|
||||
use super::Assignment;
|
||||
use crate::{ConstraintSystem, SynthesisError};
|
||||
use ff::{Field, PrimeField};
|
||||
use pairing::Engine;
|
||||
|
||||
/// Takes a sequence of booleans and exposes them as compact
|
||||
/// public inputs
|
||||
pub fn pack_into_inputs<E, CS>(
|
||||
mut cs: CS,
|
||||
bits: &[Boolean]
|
||||
) -> Result<(), SynthesisError>
|
||||
where E: Engine, CS: ConstraintSystem<E>
|
||||
pub fn pack_into_inputs<E, CS>(mut cs: CS, bits: &[Boolean]) -> Result<(), SynthesisError>
|
||||
where
|
||||
E: Engine,
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
for (i, bits) in bits.chunks(E::Fr::CAPACITY as usize).enumerate()
|
||||
{
|
||||
for (i, bits) in bits.chunks(E::Fr::CAPACITY as usize).enumerate() {
|
||||
let mut num = Num::<E>::zero();
|
||||
let mut coeff = E::Fr::one();
|
||||
for bit in bits {
|
||||
|
@ -23,44 +21,38 @@ pub fn pack_into_inputs<E, CS>(
|
|||
coeff.double();
|
||||
}
|
||||
|
||||
let input = cs.alloc_input(|| format!("input {}", i), || {
|
||||
Ok(*num.get_value().get()?)
|
||||
})?;
|
||||
let input = cs.alloc_input(|| format!("input {}", i), || Ok(*num.get_value().get()?))?;
|
||||
|
||||
// num * 1 = input
|
||||
cs.enforce(
|
||||
|| format!("packing constraint {}", i),
|
||||
|_| num.lc(E::Fr::one()),
|
||||
|lc| lc + CS::one(),
|
||||
|lc| lc + input
|
||||
|lc| lc + input,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn bytes_to_bits(bytes: &[u8]) -> Vec<bool>
|
||||
{
|
||||
bytes.iter()
|
||||
.flat_map(|&v| (0..8).rev().map(move |i| (v >> i) & 1 == 1))
|
||||
.collect()
|
||||
pub fn bytes_to_bits(bytes: &[u8]) -> Vec<bool> {
|
||||
bytes
|
||||
.iter()
|
||||
.flat_map(|&v| (0..8).rev().map(move |i| (v >> i) & 1 == 1))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn bytes_to_bits_le(bytes: &[u8]) -> Vec<bool>
|
||||
{
|
||||
bytes.iter()
|
||||
.flat_map(|&v| (0..8).map(move |i| (v >> i) & 1 == 1))
|
||||
.collect()
|
||||
pub fn bytes_to_bits_le(bytes: &[u8]) -> Vec<bool> {
|
||||
bytes
|
||||
.iter()
|
||||
.flat_map(|&v| (0..8).map(move |i| (v >> i) & 1 == 1))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn compute_multipacking<E: Engine>(
|
||||
bits: &[bool]
|
||||
) -> Vec<E::Fr>
|
||||
{
|
||||
pub fn compute_multipacking<E: Engine>(bits: &[bool]) -> Vec<E::Fr> {
|
||||
let mut result = vec![];
|
||||
|
||||
for bits in bits.chunks(E::Fr::CAPACITY as usize)
|
||||
{
|
||||
for bits in bits.chunks(E::Fr::CAPACITY as usize) {
|
||||
let mut cur = E::Fr::zero();
|
||||
let mut coeff = E::Fr::one();
|
||||
|
||||
|
@ -80,13 +72,13 @@ pub fn compute_multipacking<E: Engine>(
|
|||
|
||||
#[test]
|
||||
fn test_multipacking() {
|
||||
use crate::{ConstraintSystem};
|
||||
use pairing::bls12_381::{Bls12};
|
||||
use crate::ConstraintSystem;
|
||||
use pairing::bls12_381::Bls12;
|
||||
use rand_core::{RngCore, SeedableRng};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
|
||||
use crate::gadgets::test::*;
|
||||
use super::boolean::{AllocatedBit, Boolean};
|
||||
use crate::gadgets::test::*;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
|
@ -98,16 +90,15 @@ fn test_multipacking() {
|
|||
|
||||
let bits: Vec<bool> = (0..num_bits).map(|_| rng.next_u32() % 2 != 0).collect();
|
||||
|
||||
let circuit_bits = bits.iter().enumerate()
|
||||
.map(|(i, &b)| {
|
||||
Boolean::from(
|
||||
AllocatedBit::alloc(
|
||||
cs.namespace(|| format!("bit {}", i)),
|
||||
Some(b)
|
||||
).unwrap()
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let circuit_bits = bits
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, &b)| {
|
||||
Boolean::from(
|
||||
AllocatedBit::alloc(cs.namespace(|| format!("bit {}", i)), Some(b)).unwrap(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let expected_inputs = compute_multipacking::<Bls12>(&bits);
|
||||
|
||||
|
|
|
@ -1,78 +1,61 @@
|
|||
use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr};
|
||||
use pairing::Engine;
|
||||
|
||||
use crate::{
|
||||
SynthesisError,
|
||||
ConstraintSystem,
|
||||
LinearCombination,
|
||||
Variable
|
||||
};
|
||||
use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable};
|
||||
|
||||
use super::{
|
||||
Assignment
|
||||
};
|
||||
use super::Assignment;
|
||||
|
||||
use super::boolean::{
|
||||
self,
|
||||
Boolean,
|
||||
AllocatedBit
|
||||
};
|
||||
use super::boolean::{self, AllocatedBit, Boolean};
|
||||
|
||||
pub struct AllocatedNum<E: Engine> {
|
||||
value: Option<E::Fr>,
|
||||
variable: Variable
|
||||
variable: Variable,
|
||||
}
|
||||
|
||||
impl<E: Engine> Clone for AllocatedNum<E> {
|
||||
fn clone(&self) -> Self {
|
||||
AllocatedNum {
|
||||
value: self.value,
|
||||
variable: self.variable
|
||||
variable: self.variable,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> AllocatedNum<E> {
|
||||
pub fn alloc<CS, F>(
|
||||
mut cs: CS,
|
||||
value: F,
|
||||
) -> Result<Self, SynthesisError>
|
||||
where CS: ConstraintSystem<E>,
|
||||
F: FnOnce() -> Result<E::Fr, SynthesisError>
|
||||
pub fn alloc<CS, F>(mut cs: CS, value: F) -> Result<Self, SynthesisError>
|
||||
where
|
||||
CS: ConstraintSystem<E>,
|
||||
F: FnOnce() -> Result<E::Fr, SynthesisError>,
|
||||
{
|
||||
let mut new_value = None;
|
||||
let var = cs.alloc(|| "num", || {
|
||||
let tmp = value()?;
|
||||
let var = cs.alloc(
|
||||
|| "num",
|
||||
|| {
|
||||
let tmp = value()?;
|
||||
|
||||
new_value = Some(tmp);
|
||||
new_value = Some(tmp);
|
||||
|
||||
Ok(tmp)
|
||||
})?;
|
||||
Ok(tmp)
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(AllocatedNum {
|
||||
value: new_value,
|
||||
variable: var
|
||||
variable: var,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn inputize<CS>(
|
||||
&self,
|
||||
mut cs: CS
|
||||
) -> Result<(), SynthesisError>
|
||||
where CS: ConstraintSystem<E>
|
||||
pub fn inputize<CS>(&self, mut cs: CS) -> Result<(), SynthesisError>
|
||||
where
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
let input = cs.alloc_input(
|
||||
|| "input variable",
|
||||
|| {
|
||||
Ok(*self.value.get()?)
|
||||
}
|
||||
)?;
|
||||
let input = cs.alloc_input(|| "input variable", || Ok(*self.value.get()?))?;
|
||||
|
||||
cs.enforce(
|
||||
|| "enforce input is correct",
|
||||
|lc| lc + input,
|
||||
|lc| lc + CS::one(),
|
||||
|lc| lc + self.variable
|
||||
|lc| lc + self.variable,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
@ -83,18 +66,17 @@ impl<E: Engine> AllocatedNum<E> {
|
|||
/// order, requiring that the representation
|
||||
/// strictly exists "in the field" (i.e., a
|
||||
/// congruency is not allowed.)
|
||||
pub fn into_bits_le_strict<CS>(
|
||||
&self,
|
||||
mut cs: CS
|
||||
) -> Result<Vec<Boolean>, SynthesisError>
|
||||
where CS: ConstraintSystem<E>
|
||||
pub fn into_bits_le_strict<CS>(&self, mut cs: CS) -> Result<Vec<Boolean>, SynthesisError>
|
||||
where
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
pub fn kary_and<E, CS>(
|
||||
mut cs: CS,
|
||||
v: &[AllocatedBit]
|
||||
v: &[AllocatedBit],
|
||||
) -> Result<AllocatedBit, SynthesisError>
|
||||
where E: Engine,
|
||||
CS: ConstraintSystem<E>
|
||||
where
|
||||
E: Engine,
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
assert!(v.len() > 0);
|
||||
|
||||
|
@ -109,7 +91,7 @@ impl<E: Engine> AllocatedNum<E> {
|
|||
cur = Some(AllocatedBit::and(
|
||||
cs.namespace(|| format!("and {}", i)),
|
||||
cur.as_ref().unwrap(),
|
||||
v
|
||||
v,
|
||||
)?);
|
||||
}
|
||||
}
|
||||
|
@ -145,10 +127,7 @@ impl<E: Engine> AllocatedNum<E> {
|
|||
if b {
|
||||
// This is part of a run of ones. Let's just
|
||||
// allocate the boolean with the expected value.
|
||||
let a_bit = AllocatedBit::alloc(
|
||||
cs.namespace(|| format!("bit {}", i)),
|
||||
a_bit
|
||||
)?;
|
||||
let a_bit = AllocatedBit::alloc(cs.namespace(|| format!("bit {}", i)), a_bit)?;
|
||||
// ... and add it to the current run of ones.
|
||||
current_run.push(a_bit.clone());
|
||||
result.push(a_bit);
|
||||
|
@ -162,7 +141,7 @@ impl<E: Engine> AllocatedNum<E> {
|
|||
}
|
||||
last_run = Some(kary_and(
|
||||
cs.namespace(|| format!("run ending at {}", i)),
|
||||
¤t_run
|
||||
¤t_run,
|
||||
)?);
|
||||
current_run.truncate(0);
|
||||
}
|
||||
|
@ -175,7 +154,7 @@ impl<E: Engine> AllocatedNum<E> {
|
|||
let a_bit = AllocatedBit::alloc_conditionally(
|
||||
cs.namespace(|| format!("bit {}", i)),
|
||||
a_bit,
|
||||
&last_run.as_ref().expect("char always starts with a one")
|
||||
&last_run.as_ref().expect("char always starts with a one"),
|
||||
)?;
|
||||
result.push(a_bit);
|
||||
}
|
||||
|
@ -201,12 +180,7 @@ impl<E: Engine> AllocatedNum<E> {
|
|||
|
||||
lc = lc - self.variable;
|
||||
|
||||
cs.enforce(
|
||||
|| "unpacking constraint",
|
||||
|lc| lc,
|
||||
|lc| lc,
|
||||
|_| lc
|
||||
);
|
||||
cs.enforce(|| "unpacking constraint", |lc| lc, |lc| lc, |_| lc);
|
||||
|
||||
// Convert into booleans, and reverse for little-endian bit order
|
||||
Ok(result.into_iter().map(|b| Boolean::from(b)).rev().collect())
|
||||
|
@ -215,16 +189,11 @@ impl<E: Engine> AllocatedNum<E> {
|
|||
/// Convert the allocated number into its little-endian representation.
|
||||
/// Note that this does not strongly enforce that the commitment is
|
||||
/// "in the field."
|
||||
pub fn into_bits_le<CS>(
|
||||
&self,
|
||||
mut cs: CS
|
||||
) -> Result<Vec<Boolean>, SynthesisError>
|
||||
where CS: ConstraintSystem<E>
|
||||
pub fn into_bits_le<CS>(&self, mut cs: CS) -> Result<Vec<Boolean>, SynthesisError>
|
||||
where
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
let bits = boolean::field_into_allocated_bits_le(
|
||||
&mut cs,
|
||||
self.value
|
||||
)?;
|
||||
let bits = boolean::field_into_allocated_bits_le(&mut cs, self.value)?;
|
||||
|
||||
let mut lc = LinearCombination::zero();
|
||||
let mut coeff = E::Fr::one();
|
||||
|
@ -237,94 +206,91 @@ impl<E: Engine> AllocatedNum<E> {
|
|||
|
||||
lc = lc - self.variable;
|
||||
|
||||
cs.enforce(
|
||||
|| "unpacking constraint",
|
||||
|lc| lc,
|
||||
|lc| lc,
|
||||
|_| lc
|
||||
);
|
||||
cs.enforce(|| "unpacking constraint", |lc| lc, |lc| lc, |_| lc);
|
||||
|
||||
Ok(bits.into_iter().map(|b| Boolean::from(b)).collect())
|
||||
}
|
||||
|
||||
pub fn mul<CS>(
|
||||
&self,
|
||||
mut cs: CS,
|
||||
other: &Self
|
||||
) -> Result<Self, SynthesisError>
|
||||
where CS: ConstraintSystem<E>
|
||||
pub fn mul<CS>(&self, mut cs: CS, other: &Self) -> Result<Self, SynthesisError>
|
||||
where
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
let mut value = None;
|
||||
|
||||
let var = cs.alloc(|| "product num", || {
|
||||
let mut tmp = *self.value.get()?;
|
||||
tmp.mul_assign(other.value.get()?);
|
||||
let var = cs.alloc(
|
||||
|| "product num",
|
||||
|| {
|
||||
let mut tmp = *self.value.get()?;
|
||||
tmp.mul_assign(other.value.get()?);
|
||||
|
||||
value = Some(tmp);
|
||||
value = Some(tmp);
|
||||
|
||||
Ok(tmp)
|
||||
})?;
|
||||
Ok(tmp)
|
||||
},
|
||||
)?;
|
||||
|
||||
// Constrain: a * b = ab
|
||||
cs.enforce(
|
||||
|| "multiplication constraint",
|
||||
|lc| lc + self.variable,
|
||||
|lc| lc + other.variable,
|
||||
|lc| lc + var
|
||||
|lc| lc + var,
|
||||
);
|
||||
|
||||
Ok(AllocatedNum {
|
||||
value: value,
|
||||
variable: var
|
||||
variable: var,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn square<CS>(
|
||||
&self,
|
||||
mut cs: CS
|
||||
) -> Result<Self, SynthesisError>
|
||||
where CS: ConstraintSystem<E>
|
||||
pub fn square<CS>(&self, mut cs: CS) -> Result<Self, SynthesisError>
|
||||
where
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
let mut value = None;
|
||||
|
||||
let var = cs.alloc(|| "squared num", || {
|
||||
let mut tmp = *self.value.get()?;
|
||||
tmp.square();
|
||||
let var = cs.alloc(
|
||||
|| "squared num",
|
||||
|| {
|
||||
let mut tmp = *self.value.get()?;
|
||||
tmp.square();
|
||||
|
||||
value = Some(tmp);
|
||||
value = Some(tmp);
|
||||
|
||||
Ok(tmp)
|
||||
})?;
|
||||
Ok(tmp)
|
||||
},
|
||||
)?;
|
||||
|
||||
// Constrain: a * a = aa
|
||||
cs.enforce(
|
||||
|| "squaring constraint",
|
||||
|lc| lc + self.variable,
|
||||
|lc| lc + self.variable,
|
||||
|lc| lc + var
|
||||
|lc| lc + var,
|
||||
);
|
||||
|
||||
Ok(AllocatedNum {
|
||||
value: value,
|
||||
variable: var
|
||||
variable: var,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn assert_nonzero<CS>(
|
||||
&self,
|
||||
mut cs: CS
|
||||
) -> Result<(), SynthesisError>
|
||||
where CS: ConstraintSystem<E>
|
||||
pub fn assert_nonzero<CS>(&self, mut cs: CS) -> Result<(), SynthesisError>
|
||||
where
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
let inv = cs.alloc(|| "ephemeral inverse", || {
|
||||
let tmp = *self.value.get()?;
|
||||
|
||||
if tmp.is_zero() {
|
||||
Err(SynthesisError::DivisionByZero)
|
||||
} else {
|
||||
Ok(tmp.inverse().unwrap())
|
||||
}
|
||||
})?;
|
||||
let inv = cs.alloc(
|
||||
|| "ephemeral inverse",
|
||||
|| {
|
||||
let tmp = *self.value.get()?;
|
||||
|
||||
if tmp.is_zero() {
|
||||
Err(SynthesisError::DivisionByZero)
|
||||
} else {
|
||||
Ok(tmp.inverse().unwrap())
|
||||
}
|
||||
},
|
||||
)?;
|
||||
|
||||
// Constrain a * inv = 1, which is only valid
|
||||
// iff a has a multiplicative inverse, untrue
|
||||
|
@ -333,7 +299,7 @@ impl<E: Engine> AllocatedNum<E> {
|
|||
|| "nonzero assertion constraint",
|
||||
|lc| lc + self.variable,
|
||||
|lc| lc + inv,
|
||||
|lc| lc + CS::one()
|
||||
|lc| lc + CS::one(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
@ -346,44 +312,39 @@ impl<E: Engine> AllocatedNum<E> {
|
|||
mut cs: CS,
|
||||
a: &Self,
|
||||
b: &Self,
|
||||
condition: &Boolean
|
||||
condition: &Boolean,
|
||||
) -> Result<(Self, Self), SynthesisError>
|
||||
where CS: ConstraintSystem<E>
|
||||
where
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
let c = Self::alloc(
|
||||
cs.namespace(|| "conditional reversal result 1"),
|
||||
|| {
|
||||
if *condition.get_value().get()? {
|
||||
Ok(*b.value.get()?)
|
||||
} else {
|
||||
Ok(*a.value.get()?)
|
||||
}
|
||||
let c = Self::alloc(cs.namespace(|| "conditional reversal result 1"), || {
|
||||
if *condition.get_value().get()? {
|
||||
Ok(*b.value.get()?)
|
||||
} else {
|
||||
Ok(*a.value.get()?)
|
||||
}
|
||||
)?;
|
||||
})?;
|
||||
|
||||
cs.enforce(
|
||||
|| "first conditional reversal",
|
||||
|lc| lc + a.variable - b.variable,
|
||||
|_| condition.lc(CS::one(), E::Fr::one()),
|
||||
|lc| lc + a.variable - c.variable
|
||||
|lc| lc + a.variable - c.variable,
|
||||
);
|
||||
|
||||
let d = Self::alloc(
|
||||
cs.namespace(|| "conditional reversal result 2"),
|
||||
|| {
|
||||
if *condition.get_value().get()? {
|
||||
Ok(*a.value.get()?)
|
||||
} else {
|
||||
Ok(*b.value.get()?)
|
||||
}
|
||||
let d = Self::alloc(cs.namespace(|| "conditional reversal result 2"), || {
|
||||
if *condition.get_value().get()? {
|
||||
Ok(*a.value.get()?)
|
||||
} else {
|
||||
Ok(*b.value.get()?)
|
||||
}
|
||||
)?;
|
||||
})?;
|
||||
|
||||
cs.enforce(
|
||||
|| "second conditional reversal",
|
||||
|lc| lc + b.variable - a.variable,
|
||||
|_| condition.lc(CS::one(), E::Fr::one()),
|
||||
|lc| lc + b.variable - d.variable
|
||||
|lc| lc + b.variable - d.variable,
|
||||
);
|
||||
|
||||
Ok((c, d))
|
||||
|
@ -400,14 +361,14 @@ impl<E: Engine> AllocatedNum<E> {
|
|||
|
||||
pub struct Num<E: Engine> {
|
||||
value: Option<E::Fr>,
|
||||
lc: LinearCombination<E>
|
||||
lc: LinearCombination<E>,
|
||||
}
|
||||
|
||||
impl<E: Engine> From<AllocatedNum<E>> for Num<E> {
|
||||
fn from(num: AllocatedNum<E>) -> Num<E> {
|
||||
Num {
|
||||
value: num.value,
|
||||
lc: LinearCombination::<E>::zero() + num.variable
|
||||
lc: LinearCombination::<E>::zero() + num.variable,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -416,7 +377,7 @@ impl<E: Engine> Num<E> {
|
|||
pub fn zero() -> Self {
|
||||
Num {
|
||||
value: Some(E::Fr::zero()),
|
||||
lc: LinearCombination::zero()
|
||||
lc: LinearCombination::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -428,13 +389,7 @@ impl<E: Engine> Num<E> {
|
|||
LinearCombination::zero() + (coeff, &self.lc)
|
||||
}
|
||||
|
||||
pub fn add_bool_with_coeff(
|
||||
self,
|
||||
one: Variable,
|
||||
bit: &Boolean,
|
||||
coeff: E::Fr
|
||||
) -> Self
|
||||
{
|
||||
pub fn add_bool_with_coeff(self, one: Variable, bit: &Boolean, coeff: E::Fr) -> Self {
|
||||
let newval = match (self.value, bit.get_value()) {
|
||||
(Some(mut curval), Some(bval)) => {
|
||||
if bval {
|
||||
|
@ -442,27 +397,27 @@ impl<E: Engine> Num<E> {
|
|||
}
|
||||
|
||||
Some(curval)
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
Num {
|
||||
value: newval,
|
||||
lc: self.lc + &bit.lc(one, coeff)
|
||||
lc: self.lc + &bit.lc(one, coeff),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{ConstraintSystem};
|
||||
use crate::ConstraintSystem;
|
||||
use ff::{BitIterator, Field, PrimeField};
|
||||
use pairing::bls12_381::{Bls12, Fr};
|
||||
use rand_core::SeedableRng;
|
||||
use rand_xorshift::XorShiftRng;
|
||||
|
||||
use crate::gadgets::test::*;
|
||||
use super::{AllocatedNum, Boolean};
|
||||
use crate::gadgets::test::*;
|
||||
|
||||
#[test]
|
||||
fn test_allocated_num() {
|
||||
|
@ -491,8 +446,10 @@ mod test {
|
|||
fn test_num_multiplication() {
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let n = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::from_str("12").unwrap())).unwrap();
|
||||
let n2 = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::from_str("10").unwrap())).unwrap();
|
||||
let n =
|
||||
AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::from_str("12").unwrap())).unwrap();
|
||||
let n2 =
|
||||
AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::from_str("10").unwrap())).unwrap();
|
||||
let n3 = n.mul(&mut cs, &n2).unwrap();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
|
@ -505,8 +462,8 @@ mod test {
|
|||
#[test]
|
||||
fn test_num_conditional_reversal() {
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
{
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
@ -573,14 +530,17 @@ mod test {
|
|||
cs.set("bit 254/boolean", Fr::one());
|
||||
|
||||
// this makes the conditional boolean constraint fail
|
||||
assert_eq!(cs.which_is_unsatisfied().unwrap(), "bit 254/boolean constraint");
|
||||
assert_eq!(
|
||||
cs.which_is_unsatisfied().unwrap(),
|
||||
"bit 254/boolean constraint"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_bits() {
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for i in 0..200 {
|
||||
|
@ -597,7 +557,10 @@ mod test {
|
|||
|
||||
assert!(cs.is_satisfied());
|
||||
|
||||
for (b, a) in BitIterator::new(r.into_repr()).skip(1).zip(bits.iter().rev()) {
|
||||
for (b, a) in BitIterator::new(r.into_repr())
|
||||
.skip(1)
|
||||
.zip(bits.iter().rev())
|
||||
{
|
||||
if let &Boolean::Is(ref a) = a {
|
||||
assert_eq!(b, a.get_value().unwrap());
|
||||
} else {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use super::uint32::UInt32;
|
||||
use super::multieq::MultiEq;
|
||||
use super::boolean::Boolean;
|
||||
use super::multieq::MultiEq;
|
||||
use super::uint32::UInt32;
|
||||
use crate::{ConstraintSystem, SynthesisError};
|
||||
use pairing::Engine;
|
||||
|
||||
|
@ -12,37 +12,35 @@ const ROUND_CONSTANTS: [u32; 64] = [
|
|||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
|
||||
];
|
||||
|
||||
const IV: [u32; 8] = [
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
|
||||
];
|
||||
|
||||
pub fn sha256_block_no_padding<E, CS>(
|
||||
mut cs: CS,
|
||||
input: &[Boolean]
|
||||
input: &[Boolean],
|
||||
) -> Result<Vec<Boolean>, SynthesisError>
|
||||
where E: Engine, CS: ConstraintSystem<E>
|
||||
where
|
||||
E: Engine,
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
assert_eq!(input.len(), 512);
|
||||
|
||||
Ok(sha256_compression_function(
|
||||
&mut cs,
|
||||
&input,
|
||||
&get_sha256_iv()
|
||||
)?
|
||||
.into_iter()
|
||||
.flat_map(|e| e.into_bits_be())
|
||||
.collect())
|
||||
Ok(
|
||||
sha256_compression_function(&mut cs, &input, &get_sha256_iv())?
|
||||
.into_iter()
|
||||
.flat_map(|e| e.into_bits_be())
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn sha256<E, CS>(
|
||||
mut cs: CS,
|
||||
input: &[Boolean]
|
||||
) -> Result<Vec<Boolean>, SynthesisError>
|
||||
where E: Engine, CS: ConstraintSystem<E>
|
||||
pub fn sha256<E, CS>(mut cs: CS, input: &[Boolean]) -> Result<Vec<Boolean>, SynthesisError>
|
||||
where
|
||||
E: Engine,
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
assert!(input.len() % 8 == 0);
|
||||
|
||||
|
@ -62,16 +60,10 @@ pub fn sha256<E, CS>(
|
|||
|
||||
let mut cur = get_sha256_iv();
|
||||
for (i, block) in padded.chunks(512).enumerate() {
|
||||
cur = sha256_compression_function(
|
||||
cs.namespace(|| format!("block {}", i)),
|
||||
block,
|
||||
&cur
|
||||
)?;
|
||||
cur = sha256_compression_function(cs.namespace(|| format!("block {}", i)), block, &cur)?;
|
||||
}
|
||||
|
||||
Ok(cur.into_iter()
|
||||
.flat_map(|e| e.into_bits_be())
|
||||
.collect())
|
||||
Ok(cur.into_iter().flat_map(|e| e.into_bits_be()).collect())
|
||||
}
|
||||
|
||||
fn get_sha256_iv() -> Vec<UInt32> {
|
||||
|
@ -81,16 +73,19 @@ fn get_sha256_iv() -> Vec<UInt32> {
|
|||
fn sha256_compression_function<E, CS>(
|
||||
cs: CS,
|
||||
input: &[Boolean],
|
||||
current_hash_value: &[UInt32]
|
||||
current_hash_value: &[UInt32],
|
||||
) -> Result<Vec<UInt32>, SynthesisError>
|
||||
where E: Engine, CS: ConstraintSystem<E>
|
||||
where
|
||||
E: Engine,
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
assert_eq!(input.len(), 512);
|
||||
assert_eq!(current_hash_value.len(), 8);
|
||||
|
||||
let mut w = input.chunks(32)
|
||||
.map(|e| UInt32::from_bits_be(e))
|
||||
.collect::<Vec<_>>();
|
||||
let mut w = input
|
||||
.chunks(32)
|
||||
.map(|e| UInt32::from_bits_be(e))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// We can save some constraints by combining some of
|
||||
// the constraints in different u32 additions
|
||||
|
@ -100,30 +95,18 @@ fn sha256_compression_function<E, CS>(
|
|||
let cs = &mut cs.namespace(|| format!("w extension {}", i));
|
||||
|
||||
// s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift 3)
|
||||
let mut s0 = w[i-15].rotr(7);
|
||||
s0 = s0.xor(
|
||||
cs.namespace(|| "first xor for s0"),
|
||||
&w[i-15].rotr(18)
|
||||
)?;
|
||||
s0 = s0.xor(
|
||||
cs.namespace(|| "second xor for s0"),
|
||||
&w[i-15].shr(3)
|
||||
)?;
|
||||
let mut s0 = w[i - 15].rotr(7);
|
||||
s0 = s0.xor(cs.namespace(|| "first xor for s0"), &w[i - 15].rotr(18))?;
|
||||
s0 = s0.xor(cs.namespace(|| "second xor for s0"), &w[i - 15].shr(3))?;
|
||||
|
||||
// s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor (w[i-2] rightshift 10)
|
||||
let mut s1 = w[i-2].rotr(17);
|
||||
s1 = s1.xor(
|
||||
cs.namespace(|| "first xor for s1"),
|
||||
&w[i-2].rotr(19)
|
||||
)?;
|
||||
s1 = s1.xor(
|
||||
cs.namespace(|| "second xor for s1"),
|
||||
&w[i-2].shr(10)
|
||||
)?;
|
||||
let mut s1 = w[i - 2].rotr(17);
|
||||
s1 = s1.xor(cs.namespace(|| "first xor for s1"), &w[i - 2].rotr(19))?;
|
||||
s1 = s1.xor(cs.namespace(|| "second xor for s1"), &w[i - 2].shr(10))?;
|
||||
|
||||
let tmp = UInt32::addmany(
|
||||
cs.namespace(|| "computation of w[i]"),
|
||||
&[w[i-16].clone(), s0, w[i-7].clone(), s1]
|
||||
&[w[i - 16].clone(), s0, w[i - 7].clone(), s1],
|
||||
)?;
|
||||
|
||||
// w[i] := w[i-16] + s0 + w[i-7] + s1
|
||||
|
@ -134,29 +117,21 @@ fn sha256_compression_function<E, CS>(
|
|||
|
||||
enum Maybe {
|
||||
Deferred(Vec<UInt32>),
|
||||
Concrete(UInt32)
|
||||
Concrete(UInt32),
|
||||
}
|
||||
|
||||
impl Maybe {
|
||||
fn compute<E, CS, M>(
|
||||
self,
|
||||
cs: M,
|
||||
others: &[UInt32]
|
||||
) -> Result<UInt32, SynthesisError>
|
||||
where E: Engine,
|
||||
CS: ConstraintSystem<E>,
|
||||
M: ConstraintSystem<E, Root=MultiEq<E, CS>>
|
||||
fn compute<E, CS, M>(self, cs: M, others: &[UInt32]) -> Result<UInt32, SynthesisError>
|
||||
where
|
||||
E: Engine,
|
||||
CS: ConstraintSystem<E>,
|
||||
M: ConstraintSystem<E, Root = MultiEq<E, CS>>,
|
||||
{
|
||||
Ok(match self {
|
||||
Maybe::Concrete(ref v) => {
|
||||
return Ok(v.clone())
|
||||
},
|
||||
Maybe::Concrete(ref v) => return Ok(v.clone()),
|
||||
Maybe::Deferred(mut v) => {
|
||||
v.extend(others.into_iter().cloned());
|
||||
UInt32::addmany(
|
||||
cs,
|
||||
&v
|
||||
)?
|
||||
UInt32::addmany(cs, &v)?
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -177,22 +152,11 @@ fn sha256_compression_function<E, CS>(
|
|||
// S1 := (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25)
|
||||
let new_e = e.compute(cs.namespace(|| "deferred e computation"), &[])?;
|
||||
let mut s1 = new_e.rotr(6);
|
||||
s1 = s1.xor(
|
||||
cs.namespace(|| "first xor for s1"),
|
||||
&new_e.rotr(11)
|
||||
)?;
|
||||
s1 = s1.xor(
|
||||
cs.namespace(|| "second xor for s1"),
|
||||
&new_e.rotr(25)
|
||||
)?;
|
||||
s1 = s1.xor(cs.namespace(|| "first xor for s1"), &new_e.rotr(11))?;
|
||||
s1 = s1.xor(cs.namespace(|| "second xor for s1"), &new_e.rotr(25))?;
|
||||
|
||||
// ch := (e and f) xor ((not e) and g)
|
||||
let ch = UInt32::sha256_ch(
|
||||
cs.namespace(|| "ch"),
|
||||
&new_e,
|
||||
&f,
|
||||
&g
|
||||
)?;
|
||||
let ch = UInt32::sha256_ch(cs.namespace(|| "ch"), &new_e, &f, &g)?;
|
||||
|
||||
// temp1 := h + S1 + ch + k[i] + w[i]
|
||||
let temp1 = vec![
|
||||
|
@ -200,28 +164,17 @@ fn sha256_compression_function<E, CS>(
|
|||
s1,
|
||||
ch,
|
||||
UInt32::constant(ROUND_CONSTANTS[i]),
|
||||
w[i].clone()
|
||||
w[i].clone(),
|
||||
];
|
||||
|
||||
// S0 := (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22)
|
||||
let new_a = a.compute(cs.namespace(|| "deferred a computation"), &[])?;
|
||||
let mut s0 = new_a.rotr(2);
|
||||
s0 = s0.xor(
|
||||
cs.namespace(|| "first xor for s0"),
|
||||
&new_a.rotr(13)
|
||||
)?;
|
||||
s0 = s0.xor(
|
||||
cs.namespace(|| "second xor for s0"),
|
||||
&new_a.rotr(22)
|
||||
)?;
|
||||
s0 = s0.xor(cs.namespace(|| "first xor for s0"), &new_a.rotr(13))?;
|
||||
s0 = s0.xor(cs.namespace(|| "second xor for s0"), &new_a.rotr(22))?;
|
||||
|
||||
// maj := (a and b) xor (a and c) xor (b and c)
|
||||
let maj = UInt32::sha256_maj(
|
||||
cs.namespace(|| "maj"),
|
||||
&new_a,
|
||||
&b,
|
||||
&c
|
||||
)?;
|
||||
let maj = UInt32::sha256_maj(cs.namespace(|| "maj"), &new_a, &b, &c)?;
|
||||
|
||||
// temp2 := S0 + maj
|
||||
let temp2 = vec![s0, maj];
|
||||
|
@ -244,7 +197,13 @@ fn sha256_compression_function<E, CS>(
|
|||
d = c;
|
||||
c = b;
|
||||
b = new_a;
|
||||
a = Maybe::Deferred(temp1.iter().cloned().chain(temp2.iter().cloned()).collect::<Vec<_>>());
|
||||
a = Maybe::Deferred(
|
||||
temp1
|
||||
.iter()
|
||||
.cloned()
|
||||
.chain(temp2.iter().cloned())
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -261,42 +220,42 @@ fn sha256_compression_function<E, CS>(
|
|||
|
||||
let h0 = a.compute(
|
||||
cs.namespace(|| "deferred h0 computation"),
|
||||
&[current_hash_value[0].clone()]
|
||||
&[current_hash_value[0].clone()],
|
||||
)?;
|
||||
|
||||
let h1 = UInt32::addmany(
|
||||
cs.namespace(|| "new h1"),
|
||||
&[current_hash_value[1].clone(), b]
|
||||
&[current_hash_value[1].clone(), b],
|
||||
)?;
|
||||
|
||||
let h2 = UInt32::addmany(
|
||||
cs.namespace(|| "new h2"),
|
||||
&[current_hash_value[2].clone(), c]
|
||||
&[current_hash_value[2].clone(), c],
|
||||
)?;
|
||||
|
||||
let h3 = UInt32::addmany(
|
||||
cs.namespace(|| "new h3"),
|
||||
&[current_hash_value[3].clone(), d]
|
||||
&[current_hash_value[3].clone(), d],
|
||||
)?;
|
||||
|
||||
let h4 = e.compute(
|
||||
cs.namespace(|| "deferred h4 computation"),
|
||||
&[current_hash_value[4].clone()]
|
||||
&[current_hash_value[4].clone()],
|
||||
)?;
|
||||
|
||||
let h5 = UInt32::addmany(
|
||||
cs.namespace(|| "new h5"),
|
||||
&[current_hash_value[5].clone(), f]
|
||||
&[current_hash_value[5].clone(), f],
|
||||
)?;
|
||||
|
||||
let h6 = UInt32::addmany(
|
||||
cs.namespace(|| "new h6"),
|
||||
&[current_hash_value[6].clone(), g]
|
||||
&[current_hash_value[6].clone(), g],
|
||||
)?;
|
||||
|
||||
let h7 = UInt32::addmany(
|
||||
cs.namespace(|| "new h7"),
|
||||
&[current_hash_value[7].clone(), h]
|
||||
&[current_hash_value[7].clone(), h],
|
||||
)?;
|
||||
|
||||
Ok(vec![h0, h1, h2, h3, h4, h5, h6, h7])
|
||||
|
@ -306,8 +265,8 @@ fn sha256_compression_function<E, CS>(
|
|||
mod test {
|
||||
use super::*;
|
||||
use crate::gadgets::boolean::AllocatedBit;
|
||||
use pairing::bls12_381::Bls12;
|
||||
use crate::gadgets::test::TestConstraintSystem;
|
||||
use pairing::bls12_381::Bls12;
|
||||
use rand_core::{RngCore, SeedableRng};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
|
||||
|
@ -318,11 +277,7 @@ mod test {
|
|||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
let mut input_bits: Vec<_> = (0..512).map(|_| Boolean::Constant(false)).collect();
|
||||
input_bits[0] = Boolean::Constant(true);
|
||||
let out = sha256_compression_function(
|
||||
&mut cs,
|
||||
&input_bits,
|
||||
&iv
|
||||
).unwrap();
|
||||
let out = sha256_compression_function(&mut cs, &input_bits, &iv).unwrap();
|
||||
let out_bits: Vec<_> = out.into_iter().flat_map(|e| e.into_bits_be()).collect();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
|
@ -343,27 +298,26 @@ mod test {
|
|||
#[test]
|
||||
fn test_full_block() {
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
let iv = get_sha256_iv();
|
||||
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
let input_bits: Vec<_> = (0..512).map(|i| {
|
||||
Boolean::from(
|
||||
AllocatedBit::alloc(
|
||||
cs.namespace(|| format!("input bit {}", i)),
|
||||
Some(rng.next_u32() % 2 != 0)
|
||||
).unwrap()
|
||||
)
|
||||
}).collect();
|
||||
let input_bits: Vec<_> = (0..512)
|
||||
.map(|i| {
|
||||
Boolean::from(
|
||||
AllocatedBit::alloc(
|
||||
cs.namespace(|| format!("input bit {}", i)),
|
||||
Some(rng.next_u32() % 2 != 0),
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
sha256_compression_function(
|
||||
cs.namespace(|| "sha256"),
|
||||
&input_bits,
|
||||
&iv
|
||||
).unwrap();
|
||||
sha256_compression_function(cs.namespace(|| "sha256"), &input_bits, &iv).unwrap();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
assert_eq!(cs.num_constraints() - 512, 25840);
|
||||
|
@ -374,12 +328,11 @@ mod test {
|
|||
use sha2::{Digest, Sha256};
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0))
|
||||
{
|
||||
for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) {
|
||||
let mut h = Sha256::new();
|
||||
let data: Vec<u8> = (0..input_len).map(|_| rng.next_u32() as u8).collect();
|
||||
h.input(&data);
|
||||
|
@ -392,7 +345,11 @@ mod test {
|
|||
for bit_i in (0..8).rev() {
|
||||
let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i));
|
||||
|
||||
input_bits.push(AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)).unwrap().into());
|
||||
input_bits.push(
|
||||
AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8))
|
||||
.unwrap()
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -400,17 +357,19 @@ mod test {
|
|||
|
||||
assert!(cs.is_satisfied());
|
||||
|
||||
let mut s = hash_result.as_ref().iter()
|
||||
.flat_map(|&byte| (0..8).rev().map(move |i| (byte >> i) & 1u8 == 1u8));
|
||||
let mut s = hash_result
|
||||
.as_ref()
|
||||
.iter()
|
||||
.flat_map(|&byte| (0..8).rev().map(move |i| (byte >> i) & 1u8 == 1u8));
|
||||
|
||||
for b in r {
|
||||
match b {
|
||||
Boolean::Is(b) => {
|
||||
assert!(s.next().unwrap() == b.get_value().unwrap());
|
||||
},
|
||||
}
|
||||
Boolean::Not(b) => {
|
||||
assert!(s.next().unwrap() != b.get_value().unwrap());
|
||||
},
|
||||
}
|
||||
Boolean::Constant(b) => {
|
||||
assert!(input_len == 0);
|
||||
assert!(s.next().unwrap() == b);
|
||||
|
|
|
@ -1,13 +1,7 @@
|
|||
use ff::{Field, PrimeField, PrimeFieldRepr};
|
||||
use pairing::Engine;
|
||||
|
||||
use crate::{
|
||||
LinearCombination,
|
||||
SynthesisError,
|
||||
ConstraintSystem,
|
||||
Variable,
|
||||
Index
|
||||
};
|
||||
use crate::{ConstraintSystem, Index, LinearCombination, SynthesisError, Variable};
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Write;
|
||||
|
@ -22,7 +16,7 @@ use blake2s_simd::{Params as Blake2sParams, State as Blake2sState};
|
|||
enum NamedObject {
|
||||
Constraint(usize),
|
||||
Var(Variable),
|
||||
Namespace
|
||||
Namespace,
|
||||
}
|
||||
|
||||
/// Constraint system for testing purposes.
|
||||
|
@ -33,10 +27,10 @@ pub struct TestConstraintSystem<E: Engine> {
|
|||
LinearCombination<E>,
|
||||
LinearCombination<E>,
|
||||
LinearCombination<E>,
|
||||
String
|
||||
String,
|
||||
)>,
|
||||
inputs: Vec<(E::Fr, String)>,
|
||||
aux: Vec<(E::Fr, String)>
|
||||
aux: Vec<(E::Fr, String)>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
|
@ -48,7 +42,7 @@ impl PartialEq for OrderedVariable {
|
|||
match (self.0.get_unchecked(), other.0.get_unchecked()) {
|
||||
(Index::Input(ref a), Index::Input(ref b)) => a == b,
|
||||
(Index::Aux(ref a), Index::Aux(ref b)) => a == b,
|
||||
_ => false
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,20 +57,17 @@ impl Ord for OrderedVariable {
|
|||
(Index::Input(ref a), Index::Input(ref b)) => a.cmp(b),
|
||||
(Index::Aux(ref a), Index::Aux(ref b)) => a.cmp(b),
|
||||
(Index::Input(_), Index::Aux(_)) => Ordering::Less,
|
||||
(Index::Aux(_), Index::Input(_)) => Ordering::Greater
|
||||
(Index::Aux(_), Index::Input(_)) => Ordering::Greater,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn proc_lc<E: Engine>(
|
||||
terms: &[(Variable, E::Fr)],
|
||||
) -> BTreeMap<OrderedVariable, E::Fr>
|
||||
{
|
||||
fn proc_lc<E: Engine>(terms: &[(Variable, E::Fr)]) -> BTreeMap<OrderedVariable, E::Fr> {
|
||||
let mut map = BTreeMap::new();
|
||||
for &(var, coeff) in terms {
|
||||
map.entry(OrderedVariable(var))
|
||||
.or_insert(E::Fr::zero())
|
||||
.add_assign(&coeff);
|
||||
.or_insert(E::Fr::zero())
|
||||
.add_assign(&coeff);
|
||||
}
|
||||
|
||||
// Remove terms that have a zero coefficient to normalize
|
||||
|
@ -94,11 +85,7 @@ fn proc_lc<E: Engine>(
|
|||
map
|
||||
}
|
||||
|
||||
fn hash_lc<E: Engine>(
|
||||
terms: &[(Variable, E::Fr)],
|
||||
h: &mut Blake2sState
|
||||
)
|
||||
{
|
||||
fn hash_lc<E: Engine>(terms: &[(Variable, E::Fr)], h: &mut Blake2sState) {
|
||||
let map = proc_lc::<E>(terms);
|
||||
|
||||
let mut buf = [0u8; 9 + 32];
|
||||
|
@ -110,13 +97,13 @@ fn hash_lc<E: Engine>(
|
|||
Index::Input(i) => {
|
||||
buf[0] = b'I';
|
||||
BigEndian::write_u64(&mut buf[1..9], i as u64);
|
||||
},
|
||||
}
|
||||
Index::Aux(i) => {
|
||||
buf[0] = b'A';
|
||||
BigEndian::write_u64(&mut buf[1..9], i as u64);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
coeff.into_repr().write_be(&mut buf[9..]).unwrap();
|
||||
|
||||
h.update(&buf);
|
||||
|
@ -126,15 +113,14 @@ fn hash_lc<E: Engine>(
|
|||
fn eval_lc<E: Engine>(
|
||||
terms: &[(Variable, E::Fr)],
|
||||
inputs: &[(E::Fr, String)],
|
||||
aux: &[(E::Fr, String)]
|
||||
) -> E::Fr
|
||||
{
|
||||
aux: &[(E::Fr, String)],
|
||||
) -> E::Fr {
|
||||
let mut acc = E::Fr::zero();
|
||||
|
||||
for &(var, ref coeff) in terms {
|
||||
let mut tmp = match var.get_unchecked() {
|
||||
Index::Input(index) => inputs[index].0,
|
||||
Index::Aux(index) => aux[index].0
|
||||
Index::Aux(index) => aux[index].0,
|
||||
};
|
||||
|
||||
tmp.mul_assign(&coeff);
|
||||
|
@ -147,14 +133,17 @@ fn eval_lc<E: Engine>(
|
|||
impl<E: Engine> TestConstraintSystem<E> {
|
||||
pub fn new() -> TestConstraintSystem<E> {
|
||||
let mut map = HashMap::new();
|
||||
map.insert("ONE".into(), NamedObject::Var(TestConstraintSystem::<E>::one()));
|
||||
map.insert(
|
||||
"ONE".into(),
|
||||
NamedObject::Var(TestConstraintSystem::<E>::one()),
|
||||
);
|
||||
|
||||
TestConstraintSystem {
|
||||
named_objects: map,
|
||||
current_namespace: vec![],
|
||||
constraints: vec![],
|
||||
inputs: vec![(E::Fr::one(), "ONE".into())],
|
||||
aux: vec![]
|
||||
aux: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,9 +156,9 @@ impl<E: Engine> TestConstraintSystem<E> {
|
|||
tmp
|
||||
};
|
||||
|
||||
let powers_of_two = (0..E::Fr::NUM_BITS).map(|i| {
|
||||
E::Fr::from_str("2").unwrap().pow(&[i as u64])
|
||||
}).collect::<Vec<_>>();
|
||||
let powers_of_two = (0..E::Fr::NUM_BITS)
|
||||
.map(|i| E::Fr::from_str("2").unwrap().pow(&[i as u64]))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let pp = |s: &mut String, lc: &LinearCombination<E>| {
|
||||
write!(s, "(").unwrap();
|
||||
|
@ -196,7 +185,7 @@ impl<E: Engine> TestConstraintSystem<E> {
|
|||
match var.0.get_unchecked() {
|
||||
Index::Input(i) => {
|
||||
write!(s, "`{}`", &self.inputs[i].1).unwrap();
|
||||
},
|
||||
}
|
||||
Index::Aux(i) => {
|
||||
write!(s, "`{}`", &self.aux[i].1).unwrap();
|
||||
}
|
||||
|
@ -259,45 +248,41 @@ impl<E: Engine> TestConstraintSystem<E> {
|
|||
a.mul_assign(&b);
|
||||
|
||||
if a != c {
|
||||
return Some(&*path)
|
||||
return Some(&*path);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn is_satisfied(&self) -> bool
|
||||
{
|
||||
pub fn is_satisfied(&self) -> bool {
|
||||
self.which_is_unsatisfied().is_none()
|
||||
}
|
||||
|
||||
pub fn num_constraints(&self) -> usize
|
||||
{
|
||||
pub fn num_constraints(&self) -> usize {
|
||||
self.constraints.len()
|
||||
}
|
||||
|
||||
pub fn set(&mut self, path: &str, to: E::Fr)
|
||||
{
|
||||
pub fn set(&mut self, path: &str, to: E::Fr) {
|
||||
match self.named_objects.get(path) {
|
||||
Some(&NamedObject::Var(ref v)) => {
|
||||
match v.get_unchecked() {
|
||||
Index::Input(index) => self.inputs[index].0 = to,
|
||||
Index::Aux(index) => self.aux[index].0 = to
|
||||
}
|
||||
}
|
||||
Some(e) => panic!("tried to set path `{}` to value, but `{:?}` already exists there.", path, e),
|
||||
_ => panic!("no variable exists at path: {}", path)
|
||||
Some(&NamedObject::Var(ref v)) => match v.get_unchecked() {
|
||||
Index::Input(index) => self.inputs[index].0 = to,
|
||||
Index::Aux(index) => self.aux[index].0 = to,
|
||||
},
|
||||
Some(e) => panic!(
|
||||
"tried to set path `{}` to value, but `{:?}` already exists there.",
|
||||
path, e
|
||||
),
|
||||
_ => panic!("no variable exists at path: {}", path),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verify(&self, expected: &[E::Fr]) -> bool
|
||||
{
|
||||
pub fn verify(&self, expected: &[E::Fr]) -> bool {
|
||||
assert_eq!(expected.len() + 1, self.inputs.len());
|
||||
|
||||
for (a, b) in self.inputs.iter().skip(1).zip(expected.iter())
|
||||
{
|
||||
for (a, b) in self.inputs.iter().skip(1).zip(expected.iter()) {
|
||||
if &a.0 != b {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -308,8 +293,7 @@ impl<E: Engine> TestConstraintSystem<E> {
|
|||
self.inputs.len()
|
||||
}
|
||||
|
||||
pub fn get_input(&mut self, index: usize, path: &str) -> E::Fr
|
||||
{
|
||||
pub fn get_input(&mut self, index: usize, path: &str) -> E::Fr {
|
||||
let (assignment, name) = self.inputs[index].clone();
|
||||
|
||||
assert_eq!(path, name);
|
||||
|
@ -317,17 +301,17 @@ impl<E: Engine> TestConstraintSystem<E> {
|
|||
assignment
|
||||
}
|
||||
|
||||
pub fn get(&mut self, path: &str) -> E::Fr
|
||||
{
|
||||
pub fn get(&mut self, path: &str) -> E::Fr {
|
||||
match self.named_objects.get(path) {
|
||||
Some(&NamedObject::Var(ref v)) => {
|
||||
match v.get_unchecked() {
|
||||
Index::Input(index) => self.inputs[index].0,
|
||||
Index::Aux(index) => self.aux[index].0
|
||||
}
|
||||
}
|
||||
Some(e) => panic!("tried to get value of path `{}`, but `{:?}` exists there (not a variable)", path, e),
|
||||
_ => panic!("no variable exists at path: {}", path)
|
||||
Some(&NamedObject::Var(ref v)) => match v.get_unchecked() {
|
||||
Index::Input(index) => self.inputs[index].0,
|
||||
Index::Aux(index) => self.aux[index].0,
|
||||
},
|
||||
Some(e) => panic!(
|
||||
"tried to get value of path `{}`, but `{:?}` exists there (not a variable)",
|
||||
path, e
|
||||
),
|
||||
_ => panic!("no variable exists at path: {}", path),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -348,8 +332,7 @@ fn compute_path(ns: &[String], this: String) -> String {
|
|||
let mut name = String::new();
|
||||
|
||||
let mut needs_separation = false;
|
||||
for ns in ns.iter().chain(Some(&this).into_iter())
|
||||
{
|
||||
for ns in ns.iter().chain(Some(&this).into_iter()) {
|
||||
if needs_separation {
|
||||
name += "/";
|
||||
}
|
||||
|
@ -364,12 +347,11 @@ fn compute_path(ns: &[String], this: String) -> String {
|
|||
impl<E: Engine> ConstraintSystem<E> for TestConstraintSystem<E> {
|
||||
type Root = Self;
|
||||
|
||||
fn alloc<F, A, AR>(
|
||||
&mut self,
|
||||
annotation: A,
|
||||
f: F
|
||||
) -> Result<Variable, SynthesisError>
|
||||
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
|
||||
fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
|
||||
where
|
||||
F: FnOnce() -> Result<E::Fr, SynthesisError>,
|
||||
A: FnOnce() -> AR,
|
||||
AR: Into<String>,
|
||||
{
|
||||
let index = self.aux.len();
|
||||
let path = compute_path(&self.current_namespace, annotation().into());
|
||||
|
@ -380,12 +362,11 @@ impl<E: Engine> ConstraintSystem<E> for TestConstraintSystem<E> {
|
|||
Ok(var)
|
||||
}
|
||||
|
||||
fn alloc_input<F, A, AR>(
|
||||
&mut self,
|
||||
annotation: A,
|
||||
f: F
|
||||
) -> Result<Variable, SynthesisError>
|
||||
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
|
||||
fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
|
||||
where
|
||||
F: FnOnce() -> Result<E::Fr, SynthesisError>,
|
||||
A: FnOnce() -> AR,
|
||||
AR: Into<String>,
|
||||
{
|
||||
let index = self.inputs.len();
|
||||
let path = compute_path(&self.current_namespace, annotation().into());
|
||||
|
@ -396,17 +377,13 @@ impl<E: Engine> ConstraintSystem<E> for TestConstraintSystem<E> {
|
|||
Ok(var)
|
||||
}
|
||||
|
||||
fn enforce<A, AR, LA, LB, LC>(
|
||||
&mut self,
|
||||
annotation: 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>
|
||||
fn enforce<A, AR, LA, LB, LC>(&mut self, annotation: 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 path = compute_path(&self.current_namespace, annotation().into());
|
||||
let index = self.constraints.len();
|
||||
|
@ -420,7 +397,9 @@ impl<E: Engine> ConstraintSystem<E> for TestConstraintSystem<E> {
|
|||
}
|
||||
|
||||
fn push_namespace<NR, N>(&mut self, name_fn: N)
|
||||
where NR: Into<String>, N: FnOnce() -> NR
|
||||
where
|
||||
NR: Into<String>,
|
||||
N: FnOnce() -> NR,
|
||||
{
|
||||
let name = name_fn().into();
|
||||
let path = compute_path(&self.current_namespace, name.clone());
|
||||
|
@ -428,13 +407,11 @@ impl<E: Engine> ConstraintSystem<E> for TestConstraintSystem<E> {
|
|||
self.current_namespace.push(name);
|
||||
}
|
||||
|
||||
fn pop_namespace(&mut self)
|
||||
{
|
||||
fn pop_namespace(&mut self) {
|
||||
assert!(self.current_namespace.pop().is_some());
|
||||
}
|
||||
|
||||
fn get_root(&mut self) -> &mut Self::Root
|
||||
{
|
||||
fn get_root(&mut self) -> &mut Self::Root {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -447,28 +424,26 @@ fn test_cs() {
|
|||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
assert!(cs.is_satisfied());
|
||||
assert_eq!(cs.num_constraints(), 0);
|
||||
let a = cs.namespace(|| "a").alloc(|| "var", || Ok(Fr::from_str("10").unwrap())).unwrap();
|
||||
let b = cs.namespace(|| "b").alloc(|| "var", || Ok(Fr::from_str("4").unwrap())).unwrap();
|
||||
let c = cs.alloc(|| "product", || Ok(Fr::from_str("40").unwrap())).unwrap();
|
||||
let a = cs
|
||||
.namespace(|| "a")
|
||||
.alloc(|| "var", || Ok(Fr::from_str("10").unwrap()))
|
||||
.unwrap();
|
||||
let b = cs
|
||||
.namespace(|| "b")
|
||||
.alloc(|| "var", || Ok(Fr::from_str("4").unwrap()))
|
||||
.unwrap();
|
||||
let c = cs
|
||||
.alloc(|| "product", || Ok(Fr::from_str("40").unwrap()))
|
||||
.unwrap();
|
||||
|
||||
cs.enforce(
|
||||
|| "mult",
|
||||
|lc| lc + a,
|
||||
|lc| lc + b,
|
||||
|lc| lc + c
|
||||
);
|
||||
cs.enforce(|| "mult", |lc| lc + a, |lc| lc + b, |lc| lc + c);
|
||||
assert!(cs.is_satisfied());
|
||||
assert_eq!(cs.num_constraints(), 1);
|
||||
|
||||
cs.set("a/var", Fr::from_str("4").unwrap());
|
||||
|
||||
let one = TestConstraintSystem::<Bls12>::one();
|
||||
cs.enforce(
|
||||
|| "eq",
|
||||
|lc| lc + a,
|
||||
|lc| lc + one,
|
||||
|lc| lc + b
|
||||
);
|
||||
cs.enforce(|| "eq", |lc| lc + a, |lc| lc + one, |lc| lc + b);
|
||||
|
||||
assert!(!cs.is_satisfied());
|
||||
assert!(cs.which_is_unsatisfied() == Some("mult"));
|
||||
|
|
|
@ -1,16 +1,9 @@
|
|||
use ff::{Field, PrimeField};
|
||||
use pairing::Engine;
|
||||
|
||||
use crate::{
|
||||
SynthesisError,
|
||||
ConstraintSystem,
|
||||
LinearCombination
|
||||
};
|
||||
use crate::{ConstraintSystem, LinearCombination, SynthesisError};
|
||||
|
||||
use super::boolean::{
|
||||
Boolean,
|
||||
AllocatedBit
|
||||
};
|
||||
use super::boolean::{AllocatedBit, Boolean};
|
||||
|
||||
use super::multieq::MultiEq;
|
||||
|
||||
|
@ -20,13 +13,12 @@ use super::multieq::MultiEq;
|
|||
pub struct UInt32 {
|
||||
// Least significant bit first
|
||||
bits: Vec<Boolean>,
|
||||
value: Option<u32>
|
||||
value: Option<u32>,
|
||||
}
|
||||
|
||||
impl UInt32 {
|
||||
/// Construct a constant `UInt32` from a `u32`
|
||||
pub fn constant(value: u32) -> Self
|
||||
{
|
||||
pub fn constant(value: u32) -> Self {
|
||||
let mut bits = Vec::with_capacity(32);
|
||||
|
||||
let mut tmp = value;
|
||||
|
@ -42,17 +34,15 @@ impl UInt32 {
|
|||
|
||||
UInt32 {
|
||||
bits: bits,
|
||||
value: Some(value)
|
||||
value: Some(value),
|
||||
}
|
||||
}
|
||||
|
||||
/// Allocate a `UInt32` in the constraint system
|
||||
pub fn alloc<E, CS>(
|
||||
mut cs: CS,
|
||||
value: Option<u32>
|
||||
) -> Result<Self, SynthesisError>
|
||||
where E: Engine,
|
||||
CS: ConstraintSystem<E>
|
||||
pub fn alloc<E, CS>(mut cs: CS, value: Option<u32>) -> Result<Self, SynthesisError>
|
||||
where
|
||||
E: Engine,
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
let values = match value {
|
||||
Some(mut val) => {
|
||||
|
@ -64,23 +54,24 @@ impl UInt32 {
|
|||
}
|
||||
|
||||
v
|
||||
},
|
||||
None => vec![None; 32]
|
||||
}
|
||||
None => vec![None; 32],
|
||||
};
|
||||
|
||||
let bits = values.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, v)| {
|
||||
Ok(Boolean::from(AllocatedBit::alloc(
|
||||
cs.namespace(|| format!("allocated bit {}", i)),
|
||||
v
|
||||
)?))
|
||||
})
|
||||
.collect::<Result<Vec<_>, SynthesisError>>()?;
|
||||
let bits = values
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, v)| {
|
||||
Ok(Boolean::from(AllocatedBit::alloc(
|
||||
cs.namespace(|| format!("allocated bit {}", i)),
|
||||
v,
|
||||
)?))
|
||||
})
|
||||
.collect::<Result<Vec<_>, SynthesisError>>()?;
|
||||
|
||||
Ok(UInt32 {
|
||||
bits: bits,
|
||||
value: value
|
||||
value: value,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -96,19 +87,22 @@ impl UInt32 {
|
|||
value.as_mut().map(|v| *v <<= 1);
|
||||
|
||||
match b.get_value() {
|
||||
Some(true) => { value.as_mut().map(|v| *v |= 1); },
|
||||
Some(false) => {},
|
||||
None => { value = None; }
|
||||
Some(true) => {
|
||||
value.as_mut().map(|v| *v |= 1);
|
||||
}
|
||||
Some(false) => {}
|
||||
None => {
|
||||
value = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 {
|
||||
value: value,
|
||||
bits: bits.iter().rev().cloned().collect()
|
||||
bits: bits.iter().rev().cloned().collect(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Turns this `UInt32` into its little-endian byte order representation.
|
||||
pub fn into_bits(&self) -> Vec<Boolean> {
|
||||
self.bits.clone()
|
||||
|
@ -116,8 +110,7 @@ impl UInt32 {
|
|||
|
||||
/// Converts a little-endian byte order representation of bits into a
|
||||
/// `UInt32`.
|
||||
pub fn from_bits(bits: &[Boolean]) -> Self
|
||||
{
|
||||
pub fn from_bits(bits: &[Boolean]) -> Self {
|
||||
assert_eq!(bits.len(), 32);
|
||||
|
||||
let new_bits = bits.to_vec();
|
||||
|
@ -131,43 +124,45 @@ impl UInt32 {
|
|||
if b {
|
||||
value.as_mut().map(|v| *v |= 1);
|
||||
}
|
||||
},
|
||||
&Boolean::Is(ref b) => {
|
||||
match b.get_value() {
|
||||
Some(true) => { value.as_mut().map(|v| *v |= 1); },
|
||||
Some(false) => {},
|
||||
None => { value = None }
|
||||
}
|
||||
},
|
||||
&Boolean::Not(ref b) => {
|
||||
match b.get_value() {
|
||||
Some(false) => { value.as_mut().map(|v| *v |= 1); },
|
||||
Some(true) => {},
|
||||
None => { value = None }
|
||||
}
|
||||
}
|
||||
&Boolean::Is(ref b) => match b.get_value() {
|
||||
Some(true) => {
|
||||
value.as_mut().map(|v| *v |= 1);
|
||||
}
|
||||
Some(false) => {}
|
||||
None => value = None,
|
||||
},
|
||||
&Boolean::Not(ref b) => match b.get_value() {
|
||||
Some(false) => {
|
||||
value.as_mut().map(|v| *v |= 1);
|
||||
}
|
||||
Some(true) => {}
|
||||
None => value = None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 {
|
||||
value: value,
|
||||
bits: new_bits
|
||||
bits: new_bits,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rotr(&self, by: usize) -> Self {
|
||||
let by = by % 32;
|
||||
|
||||
let new_bits = self.bits.iter()
|
||||
.skip(by)
|
||||
.chain(self.bits.iter())
|
||||
.take(32)
|
||||
.cloned()
|
||||
.collect();
|
||||
let new_bits = self
|
||||
.bits
|
||||
.iter()
|
||||
.skip(by)
|
||||
.chain(self.bits.iter())
|
||||
.take(32)
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
UInt32 {
|
||||
bits: new_bits,
|
||||
value: self.value.map(|v| v.rotate_right(by as u32))
|
||||
value: self.value.map(|v| v.rotate_right(by as u32)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,17 +171,18 @@ impl UInt32 {
|
|||
|
||||
let fill = Boolean::constant(false);
|
||||
|
||||
let new_bits = self.bits
|
||||
.iter() // The bits are least significant first
|
||||
.skip(by) // Skip the bits that will be lost during the shift
|
||||
.chain(Some(&fill).into_iter().cycle()) // Rest will be zeros
|
||||
.take(32) // Only 32 bits needed!
|
||||
.cloned()
|
||||
.collect();
|
||||
let new_bits = self
|
||||
.bits
|
||||
.iter() // The bits are least significant first
|
||||
.skip(by) // Skip the bits that will be lost during the shift
|
||||
.chain(Some(&fill).into_iter().cycle()) // Rest will be zeros
|
||||
.take(32) // Only 32 bits needed!
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
UInt32 {
|
||||
bits: new_bits,
|
||||
value: self.value.map(|v| v >> by as u32)
|
||||
value: self.value.map(|v| v >> by as u32),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,121 +192,99 @@ impl UInt32 {
|
|||
b: &Self,
|
||||
c: &Self,
|
||||
tri_fn: F,
|
||||
circuit_fn: U
|
||||
circuit_fn: U,
|
||||
) -> Result<Self, SynthesisError>
|
||||
where E: Engine,
|
||||
CS: ConstraintSystem<E>,
|
||||
F: Fn(u32, u32, u32) -> u32,
|
||||
U: Fn(&mut CS, usize, &Boolean, &Boolean, &Boolean) -> Result<Boolean, SynthesisError>
|
||||
where
|
||||
E: Engine,
|
||||
CS: ConstraintSystem<E>,
|
||||
F: Fn(u32, u32, u32) -> u32,
|
||||
U: Fn(&mut CS, usize, &Boolean, &Boolean, &Boolean) -> Result<Boolean, SynthesisError>,
|
||||
{
|
||||
let new_value = match (a.value, b.value, c.value) {
|
||||
(Some(a), Some(b), Some(c)) => {
|
||||
Some(tri_fn(a, b, c))
|
||||
},
|
||||
_ => None
|
||||
(Some(a), Some(b), Some(c)) => Some(tri_fn(a, b, c)),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let bits = a.bits.iter()
|
||||
.zip(b.bits.iter())
|
||||
.zip(c.bits.iter())
|
||||
.enumerate()
|
||||
.map(|(i, ((a, b), c))| circuit_fn(&mut cs, i, a, b, c))
|
||||
.collect::<Result<_, _>>()?;
|
||||
let bits = a
|
||||
.bits
|
||||
.iter()
|
||||
.zip(b.bits.iter())
|
||||
.zip(c.bits.iter())
|
||||
.enumerate()
|
||||
.map(|(i, ((a, b), c))| circuit_fn(&mut cs, i, a, b, c))
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
Ok(UInt32 {
|
||||
bits: bits,
|
||||
value: new_value
|
||||
value: new_value,
|
||||
})
|
||||
}
|
||||
|
||||
/// Compute the `maj` value (a and b) xor (a and c) xor (b and c)
|
||||
/// during SHA256.
|
||||
pub fn sha256_maj<E, CS>(
|
||||
cs: CS,
|
||||
a: &Self,
|
||||
b: &Self,
|
||||
c: &Self
|
||||
) -> Result<Self, SynthesisError>
|
||||
where E: Engine,
|
||||
CS: ConstraintSystem<E>
|
||||
pub fn sha256_maj<E, CS>(cs: CS, a: &Self, b: &Self, c: &Self) -> Result<Self, SynthesisError>
|
||||
where
|
||||
E: Engine,
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
Self::triop(cs, a, b, c, |a, b, c| (a & b) ^ (a & c) ^ (b & c),
|
||||
|cs, i, a, b, c| {
|
||||
Boolean::sha256_maj(
|
||||
cs.namespace(|| format!("maj {}", i)),
|
||||
a,
|
||||
b,
|
||||
c
|
||||
)
|
||||
}
|
||||
Self::triop(
|
||||
cs,
|
||||
a,
|
||||
b,
|
||||
c,
|
||||
|a, b, c| (a & b) ^ (a & c) ^ (b & c),
|
||||
|cs, i, a, b, c| Boolean::sha256_maj(cs.namespace(|| format!("maj {}", i)), a, b, c),
|
||||
)
|
||||
}
|
||||
|
||||
/// Compute the `ch` value `(a and b) xor ((not a) and c)`
|
||||
/// during SHA256.
|
||||
pub fn sha256_ch<E, CS>(
|
||||
cs: CS,
|
||||
a: &Self,
|
||||
b: &Self,
|
||||
c: &Self
|
||||
) -> Result<Self, SynthesisError>
|
||||
where E: Engine,
|
||||
CS: ConstraintSystem<E>
|
||||
pub fn sha256_ch<E, CS>(cs: CS, a: &Self, b: &Self, c: &Self) -> Result<Self, SynthesisError>
|
||||
where
|
||||
E: Engine,
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
Self::triop(cs, a, b, c, |a, b, c| (a & b) ^ ((!a) & c),
|
||||
|cs, i, a, b, c| {
|
||||
Boolean::sha256_ch(
|
||||
cs.namespace(|| format!("ch {}", i)),
|
||||
a,
|
||||
b,
|
||||
c
|
||||
)
|
||||
}
|
||||
Self::triop(
|
||||
cs,
|
||||
a,
|
||||
b,
|
||||
c,
|
||||
|a, b, c| (a & b) ^ ((!a) & c),
|
||||
|cs, i, a, b, c| Boolean::sha256_ch(cs.namespace(|| format!("ch {}", i)), a, b, c),
|
||||
)
|
||||
}
|
||||
|
||||
/// XOR this `UInt32` with another `UInt32`
|
||||
pub fn xor<E, CS>(
|
||||
&self,
|
||||
mut cs: CS,
|
||||
other: &Self
|
||||
) -> Result<Self, SynthesisError>
|
||||
where E: Engine,
|
||||
CS: ConstraintSystem<E>
|
||||
pub fn xor<E, CS>(&self, mut cs: CS, other: &Self) -> Result<Self, SynthesisError>
|
||||
where
|
||||
E: Engine,
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
let new_value = match (self.value, other.value) {
|
||||
(Some(a), Some(b)) => {
|
||||
Some(a ^ b)
|
||||
},
|
||||
_ => None
|
||||
(Some(a), Some(b)) => Some(a ^ b),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let bits = self.bits.iter()
|
||||
.zip(other.bits.iter())
|
||||
.enumerate()
|
||||
.map(|(i, (a, b))| {
|
||||
Boolean::xor(
|
||||
cs.namespace(|| format!("xor of bit {}", i)),
|
||||
a,
|
||||
b
|
||||
)
|
||||
})
|
||||
.collect::<Result<_, _>>()?;
|
||||
let bits = self
|
||||
.bits
|
||||
.iter()
|
||||
.zip(other.bits.iter())
|
||||
.enumerate()
|
||||
.map(|(i, (a, b))| Boolean::xor(cs.namespace(|| format!("xor of bit {}", i)), a, b))
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
Ok(UInt32 {
|
||||
bits: bits,
|
||||
value: new_value
|
||||
value: new_value,
|
||||
})
|
||||
}
|
||||
|
||||
/// Perform modular addition of several `UInt32` objects.
|
||||
pub fn addmany<E, CS, M>(
|
||||
mut cs: M,
|
||||
operands: &[Self]
|
||||
) -> Result<Self, SynthesisError>
|
||||
where E: Engine,
|
||||
CS: ConstraintSystem<E>,
|
||||
M: ConstraintSystem<E, Root=MultiEq<E, CS>>
|
||||
pub fn addmany<E, CS, M>(mut cs: M, operands: &[Self]) -> Result<Self, SynthesisError>
|
||||
where
|
||||
E: Engine,
|
||||
CS: ConstraintSystem<E>,
|
||||
M: ConstraintSystem<E, Root = MultiEq<E, CS>>,
|
||||
{
|
||||
// Make some arbitrary bounds for ourselves to avoid overflows
|
||||
// in the scalar field
|
||||
|
@ -337,7 +311,7 @@ impl UInt32 {
|
|||
match op.value {
|
||||
Some(val) => {
|
||||
result_value.as_mut().map(|v| *v += val as u64);
|
||||
},
|
||||
}
|
||||
None => {
|
||||
// If any of our operands have unknown value, we won't
|
||||
// know the value of the result
|
||||
|
@ -381,7 +355,7 @@ impl UInt32 {
|
|||
// Allocate the bit
|
||||
let b = AllocatedBit::alloc(
|
||||
cs.namespace(|| format!("result bit {}", i)),
|
||||
result_value.map(|v| (v >> i) & 1 == 1)
|
||||
result_value.map(|v| (v >> i) & 1 == 1),
|
||||
)?;
|
||||
|
||||
// Add this bit to the result combination
|
||||
|
@ -402,32 +376,34 @@ impl UInt32 {
|
|||
|
||||
Ok(UInt32 {
|
||||
bits: result_bits,
|
||||
value: modular_value
|
||||
value: modular_value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::gadgets::boolean::{Boolean};
|
||||
use super::{UInt32};
|
||||
use ff::Field;
|
||||
use pairing::bls12_381::{Bls12};
|
||||
use crate::gadgets::test::*;
|
||||
use crate::{ConstraintSystem};
|
||||
use super::UInt32;
|
||||
use crate::gadgets::boolean::Boolean;
|
||||
use crate::gadgets::multieq::MultiEq;
|
||||
use crate::gadgets::test::*;
|
||||
use crate::ConstraintSystem;
|
||||
use ff::Field;
|
||||
use pairing::bls12_381::Bls12;
|
||||
use rand_core::{RngCore, SeedableRng};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
|
||||
#[test]
|
||||
fn test_uint32_from_bits_be() {
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let mut v = (0..32).map(|_| Boolean::constant(rng.next_u32() % 2 != 0)).collect::<Vec<_>>();
|
||||
let mut v = (0..32)
|
||||
.map(|_| Boolean::constant(rng.next_u32() % 2 != 0))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let b = UInt32::from_bits_be(&v);
|
||||
|
||||
|
@ -435,19 +411,18 @@ mod test {
|
|||
match bit {
|
||||
&Boolean::Constant(bit) => {
|
||||
assert!(bit == ((b.value.unwrap() >> i) & 1 == 1));
|
||||
},
|
||||
_ => unreachable!()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
let expected_to_be_same = b.into_bits_be();
|
||||
|
||||
for x in v.iter().zip(expected_to_be_same.iter())
|
||||
{
|
||||
for x in v.iter().zip(expected_to_be_same.iter()) {
|
||||
match x {
|
||||
(&Boolean::Constant(true), &Boolean::Constant(true)) => {},
|
||||
(&Boolean::Constant(false), &Boolean::Constant(false)) => {},
|
||||
_ => unreachable!()
|
||||
(&Boolean::Constant(true), &Boolean::Constant(true)) => {}
|
||||
(&Boolean::Constant(false), &Boolean::Constant(false)) => {}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -456,12 +431,14 @@ mod test {
|
|||
#[test]
|
||||
fn test_uint32_from_bits() {
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let mut v = (0..32).map(|_| Boolean::constant(rng.next_u32() % 2 != 0)).collect::<Vec<_>>();
|
||||
let mut v = (0..32)
|
||||
.map(|_| Boolean::constant(rng.next_u32() % 2 != 0))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let b = UInt32::from_bits(&v);
|
||||
|
||||
|
@ -469,19 +446,18 @@ mod test {
|
|||
match bit {
|
||||
&Boolean::Constant(bit) => {
|
||||
assert!(bit == ((b.value.unwrap() >> i) & 1 == 1));
|
||||
},
|
||||
_ => unreachable!()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
let expected_to_be_same = b.into_bits();
|
||||
|
||||
for x in v.iter().zip(expected_to_be_same.iter())
|
||||
{
|
||||
for x in v.iter().zip(expected_to_be_same.iter()) {
|
||||
match x {
|
||||
(&Boolean::Constant(true), &Boolean::Constant(true)) => {},
|
||||
(&Boolean::Constant(false), &Boolean::Constant(false)) => {},
|
||||
_ => unreachable!()
|
||||
(&Boolean::Constant(true), &Boolean::Constant(true)) => {}
|
||||
(&Boolean::Constant(false), &Boolean::Constant(false)) => {}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -490,8 +466,8 @@ mod test {
|
|||
#[test]
|
||||
fn test_uint32_xor() {
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
|
@ -518,10 +494,10 @@ mod test {
|
|||
match b {
|
||||
&Boolean::Is(ref b) => {
|
||||
assert!(b.get_value().unwrap() == (expected & 1 == 1));
|
||||
},
|
||||
}
|
||||
&Boolean::Not(ref b) => {
|
||||
assert!(!b.get_value().unwrap() == (expected & 1 == 1));
|
||||
},
|
||||
}
|
||||
&Boolean::Constant(b) => {
|
||||
assert!(b == (expected & 1 == 1));
|
||||
}
|
||||
|
@ -535,8 +511,8 @@ mod test {
|
|||
#[test]
|
||||
fn test_uint32_addmany_constants() {
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
|
@ -554,7 +530,8 @@ mod test {
|
|||
|
||||
let r = {
|
||||
let mut cs = MultiEq::new(&mut cs);
|
||||
let r = UInt32::addmany(cs.namespace(|| "addition"), &[a_bit, b_bit, c_bit]).unwrap();
|
||||
let r =
|
||||
UInt32::addmany(cs.namespace(|| "addition"), &[a_bit, b_bit, c_bit]).unwrap();
|
||||
r
|
||||
};
|
||||
|
||||
|
@ -577,8 +554,8 @@ mod test {
|
|||
#[test]
|
||||
fn test_uint32_addmany() {
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
|
@ -611,13 +588,11 @@ mod test {
|
|||
match b {
|
||||
&Boolean::Is(ref b) => {
|
||||
assert!(b.get_value().unwrap() == (expected & 1 == 1));
|
||||
},
|
||||
}
|
||||
&Boolean::Not(ref b) => {
|
||||
assert!(!b.get_value().unwrap() == (expected & 1 == 1));
|
||||
},
|
||||
&Boolean::Constant(_) => {
|
||||
unreachable!()
|
||||
}
|
||||
&Boolean::Constant(_) => unreachable!(),
|
||||
}
|
||||
|
||||
expected >>= 1;
|
||||
|
@ -637,8 +612,8 @@ mod test {
|
|||
#[test]
|
||||
fn test_uint32_rotr() {
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
let mut num = rng.next_u32();
|
||||
|
@ -656,8 +631,8 @@ mod test {
|
|||
match b {
|
||||
&Boolean::Constant(b) => {
|
||||
assert_eq!(b, tmp & 1 == 1);
|
||||
},
|
||||
_ => unreachable!()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
tmp >>= 1;
|
||||
|
@ -670,8 +645,8 @@ mod test {
|
|||
#[test]
|
||||
fn test_uint32_shr() {
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for _ in 0..50 {
|
||||
|
@ -693,8 +668,8 @@ mod test {
|
|||
#[test]
|
||||
fn test_uint32_sha256_maj() {
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
|
@ -720,10 +695,10 @@ mod test {
|
|||
match b {
|
||||
&Boolean::Is(ref b) => {
|
||||
assert!(b.get_value().unwrap() == (expected & 1 == 1));
|
||||
},
|
||||
}
|
||||
&Boolean::Not(ref b) => {
|
||||
assert!(!b.get_value().unwrap() == (expected & 1 == 1));
|
||||
},
|
||||
}
|
||||
&Boolean::Constant(b) => {
|
||||
assert!(b == (expected & 1 == 1));
|
||||
}
|
||||
|
@ -737,8 +712,8 @@ mod test {
|
|||
#[test]
|
||||
fn test_uint32_sha256_ch() {
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
|
@ -764,10 +739,10 @@ mod test {
|
|||
match b {
|
||||
&Boolean::Is(ref b) => {
|
||||
assert!(b.get_value().unwrap() == (expected & 1 == 1));
|
||||
},
|
||||
}
|
||||
&Boolean::Not(ref b) => {
|
||||
assert!(!b.get_value().unwrap() == (expected & 1 == 1));
|
||||
},
|
||||
}
|
||||
&Boolean::Constant(b) => {
|
||||
assert!(b == (expected & 1 == 1));
|
||||
}
|
||||
|
|
|
@ -6,36 +6,24 @@ use ff::{Field, PrimeField};
|
|||
use group::{CurveAffine, CurveProjective, Wnaf};
|
||||
use pairing::Engine;
|
||||
|
||||
use super::{
|
||||
Parameters,
|
||||
VerifyingKey
|
||||
};
|
||||
use super::{Parameters, VerifyingKey};
|
||||
|
||||
use ::{
|
||||
SynthesisError,
|
||||
Circuit,
|
||||
ConstraintSystem,
|
||||
LinearCombination,
|
||||
Variable,
|
||||
Index
|
||||
};
|
||||
use {Circuit, ConstraintSystem, Index, LinearCombination, SynthesisError, Variable};
|
||||
|
||||
use ::domain::{
|
||||
EvaluationDomain,
|
||||
Scalar
|
||||
};
|
||||
use domain::{EvaluationDomain, Scalar};
|
||||
|
||||
use ::multicore::{
|
||||
Worker
|
||||
};
|
||||
use multicore::Worker;
|
||||
|
||||
/// Generates a random common reference string for
|
||||
/// a circuit.
|
||||
pub fn generate_random_parameters<E, C, R>(
|
||||
circuit: C,
|
||||
rng: &mut R
|
||||
rng: &mut R,
|
||||
) -> Result<Parameters<E>, SynthesisError>
|
||||
where E: Engine, C: Circuit<E>, R: RngCore
|
||||
where
|
||||
E: Engine,
|
||||
C: Circuit<E>,
|
||||
R: RngCore,
|
||||
{
|
||||
let g1 = E::G1::random(rng);
|
||||
let g2 = E::G2::random(rng);
|
||||
|
@ -45,16 +33,7 @@ pub fn generate_random_parameters<E, C, R>(
|
|||
let delta = E::Fr::random(rng);
|
||||
let tau = E::Fr::random(rng);
|
||||
|
||||
generate_parameters::<E, C>(
|
||||
circuit,
|
||||
g1,
|
||||
g2,
|
||||
alpha,
|
||||
beta,
|
||||
gamma,
|
||||
delta,
|
||||
tau
|
||||
)
|
||||
generate_parameters::<E, C>(circuit, g1, g2, alpha, beta, gamma, delta, tau)
|
||||
}
|
||||
|
||||
/// This is our assembly structure that we'll use to synthesize the
|
||||
|
@ -68,18 +47,17 @@ struct KeypairAssembly<E: Engine> {
|
|||
ct_inputs: Vec<Vec<(E::Fr, usize)>>,
|
||||
at_aux: Vec<Vec<(E::Fr, usize)>>,
|
||||
bt_aux: Vec<Vec<(E::Fr, usize)>>,
|
||||
ct_aux: Vec<Vec<(E::Fr, usize)>>
|
||||
ct_aux: Vec<Vec<(E::Fr, usize)>>,
|
||||
}
|
||||
|
||||
impl<E: Engine> ConstraintSystem<E> for KeypairAssembly<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>
|
||||
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>,
|
||||
{
|
||||
// There is no assignment, so we don't even invoke the
|
||||
// function for obtaining one.
|
||||
|
@ -94,12 +72,11 @@ impl<E: Engine> ConstraintSystem<E> for KeypairAssembly<E> {
|
|||
Ok(Variable(Index::Aux(index)))
|
||||
}
|
||||
|
||||
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>
|
||||
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>,
|
||||
{
|
||||
// There is no assignment, so we don't even invoke the
|
||||
// function for obtaining one.
|
||||
|
@ -114,48 +91,59 @@ impl<E: Engine> ConstraintSystem<E> for KeypairAssembly<E> {
|
|||
Ok(Variable(Index::Input(index)))
|
||||
}
|
||||
|
||||
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>
|
||||
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>,
|
||||
{
|
||||
fn eval<E: Engine>(
|
||||
l: LinearCombination<E>,
|
||||
inputs: &mut [Vec<(E::Fr, usize)>],
|
||||
aux: &mut [Vec<(E::Fr, usize)>],
|
||||
this_constraint: usize
|
||||
)
|
||||
{
|
||||
this_constraint: usize,
|
||||
) {
|
||||
for (index, coeff) in l.0 {
|
||||
match index {
|
||||
Variable(Index::Input(id)) => inputs[id].push((coeff, this_constraint)),
|
||||
Variable(Index::Aux(id)) => aux[id].push((coeff, this_constraint))
|
||||
Variable(Index::Aux(id)) => aux[id].push((coeff, this_constraint)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eval(a(LinearCombination::zero()), &mut self.at_inputs, &mut self.at_aux, self.num_constraints);
|
||||
eval(b(LinearCombination::zero()), &mut self.bt_inputs, &mut self.bt_aux, self.num_constraints);
|
||||
eval(c(LinearCombination::zero()), &mut self.ct_inputs, &mut self.ct_aux, self.num_constraints);
|
||||
eval(
|
||||
a(LinearCombination::zero()),
|
||||
&mut self.at_inputs,
|
||||
&mut self.at_aux,
|
||||
self.num_constraints,
|
||||
);
|
||||
eval(
|
||||
b(LinearCombination::zero()),
|
||||
&mut self.bt_inputs,
|
||||
&mut self.bt_aux,
|
||||
self.num_constraints,
|
||||
);
|
||||
eval(
|
||||
c(LinearCombination::zero()),
|
||||
&mut self.ct_inputs,
|
||||
&mut self.ct_aux,
|
||||
self.num_constraints,
|
||||
);
|
||||
|
||||
self.num_constraints += 1;
|
||||
}
|
||||
|
||||
fn push_namespace<NR, N>(&mut self, _: N)
|
||||
where NR: Into<String>, N: FnOnce() -> NR
|
||||
where
|
||||
NR: Into<String>,
|
||||
N: FnOnce() -> NR,
|
||||
{
|
||||
// Do nothing; we don't care about namespaces in this context.
|
||||
}
|
||||
|
||||
fn pop_namespace(&mut self)
|
||||
{
|
||||
fn pop_namespace(&mut self) {
|
||||
// Do nothing; we don't care about namespaces in this context.
|
||||
}
|
||||
|
||||
|
@ -173,9 +161,11 @@ pub fn generate_parameters<E, C>(
|
|||
beta: E::Fr,
|
||||
gamma: E::Fr,
|
||||
delta: E::Fr,
|
||||
tau: E::Fr
|
||||
tau: E::Fr,
|
||||
) -> Result<Parameters<E>, SynthesisError>
|
||||
where E: Engine, C: Circuit<E>
|
||||
where
|
||||
E: Engine,
|
||||
C: Circuit<E>,
|
||||
{
|
||||
let mut assembly = KeypairAssembly {
|
||||
num_inputs: 0,
|
||||
|
@ -186,7 +176,7 @@ pub fn generate_parameters<E, C>(
|
|||
ct_inputs: vec![],
|
||||
at_aux: vec![],
|
||||
bt_aux: vec![],
|
||||
ct_aux: vec![]
|
||||
ct_aux: vec![],
|
||||
};
|
||||
|
||||
// Allocate the "one" input variable
|
||||
|
@ -198,11 +188,7 @@ pub fn generate_parameters<E, C>(
|
|||
// Input constraints to ensure full density of IC query
|
||||
// x * 0 = 0
|
||||
for i in 0..assembly.num_inputs {
|
||||
assembly.enforce(|| "",
|
||||
|lc| lc + Variable(Index::Input(i)),
|
||||
|lc| lc,
|
||||
|lc| lc,
|
||||
);
|
||||
assembly.enforce(|| "", |lc| lc + Variable(Index::Input(i)), |lc| lc, |lc| lc);
|
||||
}
|
||||
|
||||
// Create bases for blind evaluation of polynomials at tau
|
||||
|
@ -240,10 +226,9 @@ pub fn generate_parameters<E, C>(
|
|||
{
|
||||
let powers_of_tau = powers_of_tau.as_mut();
|
||||
worker.scope(powers_of_tau.len(), |scope, chunk| {
|
||||
for (i, powers_of_tau) in powers_of_tau.chunks_mut(chunk).enumerate()
|
||||
{
|
||||
for (i, powers_of_tau) in powers_of_tau.chunks_mut(chunk).enumerate() {
|
||||
scope.spawn(move || {
|
||||
let mut current_tau_power = tau.pow(&[(i*chunk) as u64]);
|
||||
let mut current_tau_power = tau.pow(&[(i * chunk) as u64]);
|
||||
|
||||
for p in powers_of_tau {
|
||||
p.0 = current_tau_power;
|
||||
|
@ -260,14 +245,15 @@ pub fn generate_parameters<E, C>(
|
|||
|
||||
// Compute the H query with multiple threads
|
||||
worker.scope(h.len(), |scope, chunk| {
|
||||
for (h, p) in h.chunks_mut(chunk).zip(powers_of_tau.as_ref().chunks(chunk))
|
||||
for (h, p) in h
|
||||
.chunks_mut(chunk)
|
||||
.zip(powers_of_tau.as_ref().chunks(chunk))
|
||||
{
|
||||
let mut g1_wnaf = g1_wnaf.shared();
|
||||
|
||||
scope.spawn(move || {
|
||||
// Set values of the H query to g1^{(tau^i * t(tau)) / delta}
|
||||
for (h, p) in h.iter_mut().zip(p.iter())
|
||||
{
|
||||
for (h, p) in h.iter_mut().zip(p.iter()) {
|
||||
// Compute final exponent
|
||||
let mut exp = p.0;
|
||||
exp.mul_assign(&coeff);
|
||||
|
@ -320,9 +306,8 @@ pub fn generate_parameters<E, C>(
|
|||
beta: &E::Fr,
|
||||
|
||||
// Worker
|
||||
worker: &Worker
|
||||
)
|
||||
{
|
||||
worker: &Worker,
|
||||
) {
|
||||
// Sanity check
|
||||
assert_eq!(a.len(), at.len());
|
||||
assert_eq!(a.len(), bt.len());
|
||||
|
@ -333,31 +318,32 @@ pub fn generate_parameters<E, C>(
|
|||
|
||||
// Evaluate polynomials in multiple threads
|
||||
worker.scope(a.len(), |scope, chunk| {
|
||||
for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a.chunks_mut(chunk)
|
||||
.zip(b_g1.chunks_mut(chunk))
|
||||
.zip(b_g2.chunks_mut(chunk))
|
||||
.zip(ext.chunks_mut(chunk))
|
||||
.zip(at.chunks(chunk))
|
||||
.zip(bt.chunks(chunk))
|
||||
.zip(ct.chunks(chunk))
|
||||
for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a
|
||||
.chunks_mut(chunk)
|
||||
.zip(b_g1.chunks_mut(chunk))
|
||||
.zip(b_g2.chunks_mut(chunk))
|
||||
.zip(ext.chunks_mut(chunk))
|
||||
.zip(at.chunks(chunk))
|
||||
.zip(bt.chunks(chunk))
|
||||
.zip(ct.chunks(chunk))
|
||||
{
|
||||
let mut g1_wnaf = g1_wnaf.shared();
|
||||
let mut g2_wnaf = g2_wnaf.shared();
|
||||
|
||||
scope.spawn(move || {
|
||||
for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a.iter_mut()
|
||||
.zip(b_g1.iter_mut())
|
||||
.zip(b_g2.iter_mut())
|
||||
.zip(ext.iter_mut())
|
||||
.zip(at.iter())
|
||||
.zip(bt.iter())
|
||||
.zip(ct.iter())
|
||||
for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a
|
||||
.iter_mut()
|
||||
.zip(b_g1.iter_mut())
|
||||
.zip(b_g2.iter_mut())
|
||||
.zip(ext.iter_mut())
|
||||
.zip(at.iter())
|
||||
.zip(bt.iter())
|
||||
.zip(ct.iter())
|
||||
{
|
||||
fn eval_at_tau<E: Engine>(
|
||||
powers_of_tau: &[Scalar<E>],
|
||||
p: &[(E::Fr, usize)]
|
||||
) -> E::Fr
|
||||
{
|
||||
p: &[(E::Fr, usize)],
|
||||
) -> E::Fr {
|
||||
let mut acc = E::Fr::zero();
|
||||
|
||||
for &(ref coeff, index) in p {
|
||||
|
@ -422,7 +408,7 @@ pub fn generate_parameters<E, C>(
|
|||
&gamma_inverse,
|
||||
&alpha,
|
||||
&beta,
|
||||
&worker
|
||||
&worker,
|
||||
);
|
||||
|
||||
// Evaluate for auxiliary variables.
|
||||
|
@ -440,7 +426,7 @@ pub fn generate_parameters<E, C>(
|
|||
&delta_inverse,
|
||||
&alpha,
|
||||
&beta,
|
||||
&worker
|
||||
&worker,
|
||||
);
|
||||
|
||||
// Don't allow any elements be unconstrained, so that
|
||||
|
@ -461,7 +447,7 @@ pub fn generate_parameters<E, C>(
|
|||
gamma_g2: g2.mul(gamma).into_affine(),
|
||||
delta_g1: g1.mul(delta).into_affine(),
|
||||
delta_g2: g2.mul(delta).into_affine(),
|
||||
ic: ic.into_iter().map(|e| e.into_affine()).collect()
|
||||
ic: ic.into_iter().map(|e| e.into_affine()).collect(),
|
||||
};
|
||||
|
||||
Ok(Parameters {
|
||||
|
@ -470,8 +456,23 @@ pub fn generate_parameters<E, C>(
|
|||
l: Arc::new(l.into_iter().map(|e| e.into_affine()).collect()),
|
||||
|
||||
// Filter points at infinity away from A/B queries
|
||||
a: Arc::new(a.into_iter().filter(|e| !e.is_zero()).map(|e| e.into_affine()).collect()),
|
||||
b_g1: Arc::new(b_g1.into_iter().filter(|e| !e.is_zero()).map(|e| e.into_affine()).collect()),
|
||||
b_g2: Arc::new(b_g2.into_iter().filter(|e| !e.is_zero()).map(|e| e.into_affine()).collect())
|
||||
a: Arc::new(
|
||||
a.into_iter()
|
||||
.filter(|e| !e.is_zero())
|
||||
.map(|e| e.into_affine())
|
||||
.collect(),
|
||||
),
|
||||
b_g1: Arc::new(
|
||||
b_g1.into_iter()
|
||||
.filter(|e| !e.is_zero())
|
||||
.map(|e| e.into_affine())
|
||||
.collect(),
|
||||
),
|
||||
b_g2: Arc::new(
|
||||
b_g2.into_iter()
|
||||
.filter(|e| !e.is_zero())
|
||||
.map(|e| e.into_affine())
|
||||
.collect(),
|
||||
),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,17 +1,12 @@
|
|||
use group::{CurveAffine, EncodedPoint};
|
||||
use pairing::{
|
||||
Engine,
|
||||
PairingCurveAffine,
|
||||
};
|
||||
use pairing::{Engine, PairingCurveAffine};
|
||||
|
||||
use ::{
|
||||
SynthesisError
|
||||
};
|
||||
use SynthesisError;
|
||||
|
||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
use multiexp::SourceBuilder;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::sync::Arc;
|
||||
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
@ -28,23 +23,17 @@ pub use self::verifier::*;
|
|||
pub struct Proof<E: Engine> {
|
||||
pub a: E::G1Affine,
|
||||
pub b: E::G2Affine,
|
||||
pub c: E::G1Affine
|
||||
pub c: E::G1Affine,
|
||||
}
|
||||
|
||||
impl<E: Engine> PartialEq for Proof<E> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.a == other.a &&
|
||||
self.b == other.b &&
|
||||
self.c == other.c
|
||||
self.a == other.a && self.b == other.b && self.c == other.c
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> Proof<E> {
|
||||
pub fn write<W: Write>(
|
||||
&self,
|
||||
mut writer: W
|
||||
) -> io::Result<()>
|
||||
{
|
||||
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||
writer.write_all(self.a.into_compressed().as_ref())?;
|
||||
writer.write_all(self.b.into_compressed().as_ref())?;
|
||||
writer.write_all(self.c.into_compressed().as_ref())?;
|
||||
|
@ -52,48 +41,56 @@ impl<E: Engine> Proof<E> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read<R: Read>(
|
||||
mut reader: R
|
||||
) -> io::Result<Self>
|
||||
{
|
||||
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
|
||||
let mut g1_repr = <E::G1Affine as CurveAffine>::Compressed::empty();
|
||||
let mut g2_repr = <E::G2Affine as CurveAffine>::Compressed::empty();
|
||||
|
||||
reader.read_exact(g1_repr.as_mut())?;
|
||||
let a = g1_repr
|
||||
.into_affine()
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
|
||||
.and_then(|e| if e.is_zero() {
|
||||
Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity"))
|
||||
.into_affine()
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
|
||||
.and_then(|e| {
|
||||
if e.is_zero() {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"point at infinity",
|
||||
))
|
||||
} else {
|
||||
Ok(e)
|
||||
})?;
|
||||
}
|
||||
})?;
|
||||
|
||||
reader.read_exact(g2_repr.as_mut())?;
|
||||
let b = g2_repr
|
||||
.into_affine()
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
|
||||
.and_then(|e| if e.is_zero() {
|
||||
Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity"))
|
||||
.into_affine()
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
|
||||
.and_then(|e| {
|
||||
if e.is_zero() {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"point at infinity",
|
||||
))
|
||||
} else {
|
||||
Ok(e)
|
||||
})?;
|
||||
}
|
||||
})?;
|
||||
|
||||
reader.read_exact(g1_repr.as_mut())?;
|
||||
let c = g1_repr
|
||||
.into_affine()
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
|
||||
.and_then(|e| if e.is_zero() {
|
||||
Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity"))
|
||||
.into_affine()
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
|
||||
.and_then(|e| {
|
||||
if e.is_zero() {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"point at infinity",
|
||||
))
|
||||
} else {
|
||||
Ok(e)
|
||||
})?;
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(Proof {
|
||||
a: a,
|
||||
b: b,
|
||||
c: c
|
||||
})
|
||||
Ok(Proof { a: a, b: b, c: c })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,27 +119,23 @@ pub struct VerifyingKey<E: Engine> {
|
|||
// for all public inputs. Because all public inputs have a dummy constraint,
|
||||
// this is the same size as the number of inputs, and never contains points
|
||||
// at infinity.
|
||||
pub ic: Vec<E::G1Affine>
|
||||
pub ic: Vec<E::G1Affine>,
|
||||
}
|
||||
|
||||
impl<E: Engine> PartialEq for VerifyingKey<E> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.alpha_g1 == other.alpha_g1 &&
|
||||
self.beta_g1 == other.beta_g1 &&
|
||||
self.beta_g2 == other.beta_g2 &&
|
||||
self.gamma_g2 == other.gamma_g2 &&
|
||||
self.delta_g1 == other.delta_g1 &&
|
||||
self.delta_g2 == other.delta_g2 &&
|
||||
self.ic == other.ic
|
||||
self.alpha_g1 == other.alpha_g1
|
||||
&& self.beta_g1 == other.beta_g1
|
||||
&& self.beta_g2 == other.beta_g2
|
||||
&& self.gamma_g2 == other.gamma_g2
|
||||
&& self.delta_g1 == other.delta_g1
|
||||
&& self.delta_g2 == other.delta_g2
|
||||
&& self.ic == other.ic
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> VerifyingKey<E> {
|
||||
pub fn write<W: Write>(
|
||||
&self,
|
||||
mut writer: W
|
||||
) -> io::Result<()>
|
||||
{
|
||||
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||
writer.write_all(self.alpha_g1.into_uncompressed().as_ref())?;
|
||||
writer.write_all(self.beta_g1.into_uncompressed().as_ref())?;
|
||||
writer.write_all(self.beta_g2.into_uncompressed().as_ref())?;
|
||||
|
@ -157,30 +150,39 @@ impl<E: Engine> VerifyingKey<E> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read<R: Read>(
|
||||
mut reader: R
|
||||
) -> io::Result<Self>
|
||||
{
|
||||
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
|
||||
let mut g1_repr = <E::G1Affine as CurveAffine>::Uncompressed::empty();
|
||||
let mut g2_repr = <E::G2Affine as CurveAffine>::Uncompressed::empty();
|
||||
|
||||
reader.read_exact(g1_repr.as_mut())?;
|
||||
let alpha_g1 = g1_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
let alpha_g1 = g1_repr
|
||||
.into_affine()
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
|
||||
reader.read_exact(g1_repr.as_mut())?;
|
||||
let beta_g1 = g1_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
let beta_g1 = g1_repr
|
||||
.into_affine()
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
|
||||
reader.read_exact(g2_repr.as_mut())?;
|
||||
let beta_g2 = g2_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
let beta_g2 = g2_repr
|
||||
.into_affine()
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
|
||||
reader.read_exact(g2_repr.as_mut())?;
|
||||
let gamma_g2 = g2_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
let gamma_g2 = g2_repr
|
||||
.into_affine()
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
|
||||
reader.read_exact(g1_repr.as_mut())?;
|
||||
let delta_g1 = g1_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
let delta_g1 = g1_repr
|
||||
.into_affine()
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
|
||||
reader.read_exact(g2_repr.as_mut())?;
|
||||
let delta_g2 = g2_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
let delta_g2 = g2_repr
|
||||
.into_affine()
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
|
||||
let ic_len = reader.read_u32::<BigEndian>()? as usize;
|
||||
|
||||
|
@ -189,13 +191,18 @@ impl<E: Engine> VerifyingKey<E> {
|
|||
for _ in 0..ic_len {
|
||||
reader.read_exact(g1_repr.as_mut())?;
|
||||
let g1 = g1_repr
|
||||
.into_affine()
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
|
||||
.and_then(|e| if e.is_zero() {
|
||||
Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity"))
|
||||
} else {
|
||||
Ok(e)
|
||||
})?;
|
||||
.into_affine()
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
|
||||
.and_then(|e| {
|
||||
if e.is_zero() {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"point at infinity",
|
||||
))
|
||||
} else {
|
||||
Ok(e)
|
||||
}
|
||||
})?;
|
||||
|
||||
ic.push(g1);
|
||||
}
|
||||
|
@ -207,7 +214,7 @@ impl<E: Engine> VerifyingKey<E> {
|
|||
gamma_g2: gamma_g2,
|
||||
delta_g1: delta_g1,
|
||||
delta_g2: delta_g2,
|
||||
ic: ic
|
||||
ic: ic,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -216,7 +223,7 @@ impl<E: Engine> VerifyingKey<E> {
|
|||
pub struct Parameters<E: Engine> {
|
||||
pub vk: VerifyingKey<E>,
|
||||
|
||||
// Elements of the form ((tau^i * t(tau)) / delta) for i between 0 and
|
||||
// Elements of the form ((tau^i * t(tau)) / delta) for i between 0 and
|
||||
// m-2 inclusive. Never contains points at infinity.
|
||||
pub h: Arc<Vec<E::G1Affine>>,
|
||||
|
||||
|
@ -234,26 +241,22 @@ pub struct Parameters<E: Engine> {
|
|||
// G1 and G2 for C/B queries, respectively. Never contains points at
|
||||
// infinity for the same reason as the "A" polynomials.
|
||||
pub b_g1: Arc<Vec<E::G1Affine>>,
|
||||
pub b_g2: Arc<Vec<E::G2Affine>>
|
||||
pub b_g2: Arc<Vec<E::G2Affine>>,
|
||||
}
|
||||
|
||||
impl<E: Engine> PartialEq for Parameters<E> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.vk == other.vk &&
|
||||
self.h == other.h &&
|
||||
self.l == other.l &&
|
||||
self.a == other.a &&
|
||||
self.b_g1 == other.b_g1 &&
|
||||
self.b_g2 == other.b_g2
|
||||
self.vk == other.vk
|
||||
&& self.h == other.h
|
||||
&& self.l == other.l
|
||||
&& self.a == other.a
|
||||
&& self.b_g1 == other.b_g1
|
||||
&& self.b_g2 == other.b_g2
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> Parameters<E> {
|
||||
pub fn write<W: Write>(
|
||||
&self,
|
||||
mut writer: W
|
||||
) -> io::Result<()>
|
||||
{
|
||||
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||
self.vk.write(&mut writer)?;
|
||||
|
||||
writer.write_u32::<BigEndian>(self.h.len() as u32)?;
|
||||
|
@ -284,27 +287,26 @@ impl<E: Engine> Parameters<E> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read<R: Read>(
|
||||
mut reader: R,
|
||||
checked: bool
|
||||
) -> io::Result<Self>
|
||||
{
|
||||
pub fn read<R: Read>(mut reader: R, checked: bool) -> io::Result<Self> {
|
||||
let read_g1 = |reader: &mut R| -> io::Result<E::G1Affine> {
|
||||
let mut repr = <E::G1Affine as CurveAffine>::Uncompressed::empty();
|
||||
reader.read_exact(repr.as_mut())?;
|
||||
|
||||
if checked {
|
||||
repr
|
||||
.into_affine()
|
||||
repr.into_affine()
|
||||
} else {
|
||||
repr
|
||||
.into_affine_unchecked()
|
||||
repr.into_affine_unchecked()
|
||||
}
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
|
||||
.and_then(|e| if e.is_zero() {
|
||||
Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity"))
|
||||
} else {
|
||||
Ok(e)
|
||||
.and_then(|e| {
|
||||
if e.is_zero() {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"point at infinity",
|
||||
))
|
||||
} else {
|
||||
Ok(e)
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
|
@ -313,17 +315,20 @@ impl<E: Engine> Parameters<E> {
|
|||
reader.read_exact(repr.as_mut())?;
|
||||
|
||||
if checked {
|
||||
repr
|
||||
.into_affine()
|
||||
repr.into_affine()
|
||||
} else {
|
||||
repr
|
||||
.into_affine_unchecked()
|
||||
repr.into_affine_unchecked()
|
||||
}
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
|
||||
.and_then(|e| if e.is_zero() {
|
||||
Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity"))
|
||||
} else {
|
||||
Ok(e)
|
||||
.and_then(|e| {
|
||||
if e.is_zero() {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"point at infinity",
|
||||
))
|
||||
} else {
|
||||
Ok(e)
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
|
@ -376,7 +381,7 @@ impl<E: Engine> Parameters<E> {
|
|||
l: Arc::new(l),
|
||||
a: Arc::new(a),
|
||||
b_g1: Arc::new(b_g1),
|
||||
b_g2: Arc::new(b_g2)
|
||||
b_g2: Arc::new(b_g2),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -389,39 +394,30 @@ pub struct PreparedVerifyingKey<E: Engine> {
|
|||
/// -delta in G2
|
||||
neg_delta_g2: <E::G2Affine as PairingCurveAffine>::Prepared,
|
||||
/// Copy of IC from `VerifiyingKey`.
|
||||
ic: Vec<E::G1Affine>
|
||||
ic: Vec<E::G1Affine>,
|
||||
}
|
||||
|
||||
pub trait ParameterSource<E: Engine> {
|
||||
type G1Builder: SourceBuilder<E::G1Affine>;
|
||||
type G2Builder: SourceBuilder<E::G2Affine>;
|
||||
|
||||
fn get_vk(
|
||||
&mut self,
|
||||
num_ic: usize
|
||||
) -> Result<VerifyingKey<E>, SynthesisError>;
|
||||
fn get_h(
|
||||
&mut self,
|
||||
num_h: usize
|
||||
) -> Result<Self::G1Builder, SynthesisError>;
|
||||
fn get_l(
|
||||
&mut self,
|
||||
num_l: usize
|
||||
) -> Result<Self::G1Builder, SynthesisError>;
|
||||
fn get_vk(&mut self, num_ic: usize) -> Result<VerifyingKey<E>, SynthesisError>;
|
||||
fn get_h(&mut self, num_h: usize) -> Result<Self::G1Builder, SynthesisError>;
|
||||
fn get_l(&mut self, num_l: usize) -> Result<Self::G1Builder, SynthesisError>;
|
||||
fn get_a(
|
||||
&mut self,
|
||||
num_inputs: usize,
|
||||
num_aux: usize
|
||||
num_aux: usize,
|
||||
) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError>;
|
||||
fn get_b_g1(
|
||||
&mut self,
|
||||
num_inputs: usize,
|
||||
num_aux: usize
|
||||
num_aux: usize,
|
||||
) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError>;
|
||||
fn get_b_g2(
|
||||
&mut self,
|
||||
num_inputs: usize,
|
||||
num_aux: usize
|
||||
num_aux: usize,
|
||||
) -> Result<(Self::G2Builder, Self::G2Builder), SynthesisError>;
|
||||
}
|
||||
|
||||
|
@ -429,54 +425,39 @@ impl<'a, E: Engine> ParameterSource<E> for &'a Parameters<E> {
|
|||
type G1Builder = (Arc<Vec<E::G1Affine>>, usize);
|
||||
type G2Builder = (Arc<Vec<E::G2Affine>>, usize);
|
||||
|
||||
fn get_vk(
|
||||
&mut self,
|
||||
_: usize
|
||||
) -> Result<VerifyingKey<E>, SynthesisError>
|
||||
{
|
||||
fn get_vk(&mut self, _: usize) -> Result<VerifyingKey<E>, SynthesisError> {
|
||||
Ok(self.vk.clone())
|
||||
}
|
||||
|
||||
fn get_h(
|
||||
&mut self,
|
||||
_: usize
|
||||
) -> Result<Self::G1Builder, SynthesisError>
|
||||
{
|
||||
fn get_h(&mut self, _: usize) -> Result<Self::G1Builder, SynthesisError> {
|
||||
Ok((self.h.clone(), 0))
|
||||
}
|
||||
|
||||
fn get_l(
|
||||
&mut self,
|
||||
_: usize
|
||||
) -> Result<Self::G1Builder, SynthesisError>
|
||||
{
|
||||
fn get_l(&mut self, _: usize) -> Result<Self::G1Builder, SynthesisError> {
|
||||
Ok((self.l.clone(), 0))
|
||||
}
|
||||
|
||||
fn get_a(
|
||||
&mut self,
|
||||
num_inputs: usize,
|
||||
_: usize
|
||||
) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError>
|
||||
{
|
||||
_: usize,
|
||||
) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError> {
|
||||
Ok(((self.a.clone(), 0), (self.a.clone(), num_inputs)))
|
||||
}
|
||||
|
||||
fn get_b_g1(
|
||||
&mut self,
|
||||
num_inputs: usize,
|
||||
_: usize
|
||||
) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError>
|
||||
{
|
||||
_: usize,
|
||||
) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError> {
|
||||
Ok(((self.b_g1.clone(), 0), (self.b_g1.clone(), num_inputs)))
|
||||
}
|
||||
|
||||
fn get_b_g2(
|
||||
&mut self,
|
||||
num_inputs: usize,
|
||||
_: usize
|
||||
) -> Result<(Self::G2Builder, Self::G2Builder), SynthesisError>
|
||||
{
|
||||
_: usize,
|
||||
) -> Result<(Self::G2Builder, Self::G2Builder), SynthesisError> {
|
||||
Ok(((self.b_g2.clone(), 0), (self.b_g2.clone(), num_inputs)))
|
||||
}
|
||||
}
|
||||
|
@ -484,41 +465,38 @@ impl<'a, E: Engine> ParameterSource<E> for &'a Parameters<E> {
|
|||
#[cfg(test)]
|
||||
mod test_with_bls12_381 {
|
||||
use super::*;
|
||||
use {Circuit, SynthesisError, ConstraintSystem};
|
||||
use {Circuit, ConstraintSystem, SynthesisError};
|
||||
|
||||
use ff::Field;
|
||||
use rand::{thread_rng};
|
||||
use pairing::bls12_381::{Bls12, Fr};
|
||||
use rand::thread_rng;
|
||||
|
||||
#[test]
|
||||
fn serialization() {
|
||||
struct MySillyCircuit<E: Engine> {
|
||||
a: Option<E::Fr>,
|
||||
b: Option<E::Fr>
|
||||
b: Option<E::Fr>,
|
||||
}
|
||||
|
||||
impl<E: Engine> Circuit<E> for MySillyCircuit<E> {
|
||||
fn synthesize<CS: ConstraintSystem<E>>(
|
||||
self,
|
||||
cs: &mut CS
|
||||
) -> Result<(), SynthesisError>
|
||||
{
|
||||
cs: &mut CS,
|
||||
) -> Result<(), SynthesisError> {
|
||||
let a = cs.alloc(|| "a", || self.a.ok_or(SynthesisError::AssignmentMissing))?;
|
||||
let b = cs.alloc(|| "b", || self.b.ok_or(SynthesisError::AssignmentMissing))?;
|
||||
let c = cs.alloc_input(|| "c", || {
|
||||
let mut a = self.a.ok_or(SynthesisError::AssignmentMissing)?;
|
||||
let b = self.b.ok_or(SynthesisError::AssignmentMissing)?;
|
||||
let c = cs.alloc_input(
|
||||
|| "c",
|
||||
|| {
|
||||
let mut a = self.a.ok_or(SynthesisError::AssignmentMissing)?;
|
||||
let b = self.b.ok_or(SynthesisError::AssignmentMissing)?;
|
||||
|
||||
a.mul_assign(&b);
|
||||
Ok(a)
|
||||
})?;
|
||||
a.mul_assign(&b);
|
||||
Ok(a)
|
||||
},
|
||||
)?;
|
||||
|
||||
cs.enforce(
|
||||
|| "a*b=c",
|
||||
|lc| lc + a,
|
||||
|lc| lc + b,
|
||||
|lc| lc + c
|
||||
);
|
||||
cs.enforce(|| "a*b=c", |lc| lc + a, |lc| lc + b, |lc| lc + c);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -526,10 +504,9 @@ mod test_with_bls12_381 {
|
|||
|
||||
let rng = &mut thread_rng();
|
||||
|
||||
let params = generate_random_parameters::<Bls12, _, _>(
|
||||
MySillyCircuit { a: None, b: None },
|
||||
rng
|
||||
).unwrap();
|
||||
let params =
|
||||
generate_random_parameters::<Bls12, _, _>(MySillyCircuit { a: None, b: None }, rng)
|
||||
.unwrap();
|
||||
|
||||
{
|
||||
let mut v = vec![];
|
||||
|
@ -555,11 +532,12 @@ mod test_with_bls12_381 {
|
|||
let proof = create_random_proof(
|
||||
MySillyCircuit {
|
||||
a: Some(a),
|
||||
b: Some(b)
|
||||
b: Some(b),
|
||||
},
|
||||
¶ms,
|
||||
rng
|
||||
).unwrap();
|
||||
rng,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut v = vec![];
|
||||
proof.write(&mut v).unwrap();
|
||||
|
|
|
@ -8,43 +8,23 @@ use ff::{Field, PrimeField};
|
|||
use group::{CurveAffine, CurveProjective};
|
||||
use pairing::Engine;
|
||||
|
||||
use super::{
|
||||
ParameterSource,
|
||||
Proof
|
||||
};
|
||||
use super::{ParameterSource, Proof};
|
||||
|
||||
use ::{
|
||||
SynthesisError,
|
||||
Circuit,
|
||||
ConstraintSystem,
|
||||
LinearCombination,
|
||||
Variable,
|
||||
Index
|
||||
};
|
||||
use {Circuit, ConstraintSystem, Index, LinearCombination, SynthesisError, Variable};
|
||||
|
||||
use ::domain::{
|
||||
EvaluationDomain,
|
||||
Scalar
|
||||
};
|
||||
use domain::{EvaluationDomain, Scalar};
|
||||
|
||||
use ::multiexp::{
|
||||
DensityTracker,
|
||||
FullDensity,
|
||||
multiexp
|
||||
};
|
||||
use multiexp::{multiexp, DensityTracker, FullDensity};
|
||||
|
||||
use ::multicore::{
|
||||
Worker
|
||||
};
|
||||
use multicore::Worker;
|
||||
|
||||
fn eval<E: Engine>(
|
||||
lc: &LinearCombination<E>,
|
||||
mut input_density: Option<&mut DensityTracker>,
|
||||
mut aux_density: Option<&mut DensityTracker>,
|
||||
input_assignment: &[E::Fr],
|
||||
aux_assignment: &[E::Fr]
|
||||
) -> E::Fr
|
||||
{
|
||||
aux_assignment: &[E::Fr],
|
||||
) -> E::Fr {
|
||||
let mut acc = E::Fr::zero();
|
||||
|
||||
for &(index, coeff) in lc.0.iter() {
|
||||
|
@ -56,7 +36,7 @@ fn eval<E: Engine>(
|
|||
if let Some(ref mut v) = input_density {
|
||||
v.inc(i);
|
||||
}
|
||||
},
|
||||
}
|
||||
Variable(Index::Aux(i)) => {
|
||||
tmp = aux_assignment[i];
|
||||
if let Some(ref mut v) = aux_density {
|
||||
|
@ -66,10 +46,10 @@ fn eval<E: Engine>(
|
|||
}
|
||||
|
||||
if coeff == E::Fr::one() {
|
||||
acc.add_assign(&tmp);
|
||||
acc.add_assign(&tmp);
|
||||
} else {
|
||||
tmp.mul_assign(&coeff);
|
||||
acc.add_assign(&tmp);
|
||||
tmp.mul_assign(&coeff);
|
||||
acc.add_assign(&tmp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,18 +69,17 @@ struct ProvingAssignment<E: Engine> {
|
|||
|
||||
// Assignments of variables
|
||||
input_assignment: Vec<E::Fr>,
|
||||
aux_assignment: Vec<E::Fr>
|
||||
aux_assignment: Vec<E::Fr>,
|
||||
}
|
||||
|
||||
impl<E: Engine> ConstraintSystem<E> for ProvingAssignment<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>
|
||||
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>,
|
||||
{
|
||||
self.aux_assignment.push(f()?);
|
||||
self.a_aux_density.add_element();
|
||||
|
@ -109,12 +88,11 @@ impl<E: Engine> ConstraintSystem<E> for ProvingAssignment<E> {
|
|||
Ok(Variable(Index::Aux(self.aux_assignment.len() - 1)))
|
||||
}
|
||||
|
||||
fn alloc_input<F, A, AR>(
|
||||
&mut self,
|
||||
_: A,
|
||||
f: F
|
||||
) -> Result<Variable, SynthesisError>
|
||||
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
|
||||
fn alloc_input<F, A, AR>(&mut self, _: A, f: F) -> Result<Variable, SynthesisError>
|
||||
where
|
||||
F: FnOnce() -> Result<E::Fr, SynthesisError>,
|
||||
A: FnOnce() -> AR,
|
||||
AR: Into<String>,
|
||||
{
|
||||
self.input_assignment.push(f()?);
|
||||
self.b_input_density.add_element();
|
||||
|
@ -122,17 +100,13 @@ impl<E: Engine> ConstraintSystem<E> for ProvingAssignment<E> {
|
|||
Ok(Variable(Index::Input(self.input_assignment.len() - 1)))
|
||||
}
|
||||
|
||||
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>
|
||||
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());
|
||||
|
@ -146,14 +120,14 @@ impl<E: Engine> ConstraintSystem<E> for ProvingAssignment<E> {
|
|||
None,
|
||||
Some(&mut self.a_aux_density),
|
||||
&self.input_assignment,
|
||||
&self.aux_assignment
|
||||
&self.aux_assignment,
|
||||
)));
|
||||
self.b.push(Scalar(eval(
|
||||
&b,
|
||||
Some(&mut self.b_input_density),
|
||||
Some(&mut self.b_aux_density),
|
||||
&self.input_assignment,
|
||||
&self.aux_assignment
|
||||
&self.aux_assignment,
|
||||
)));
|
||||
self.c.push(Scalar(eval(
|
||||
&c,
|
||||
|
@ -164,18 +138,19 @@ impl<E: Engine> ConstraintSystem<E> for ProvingAssignment<E> {
|
|||
None,
|
||||
None,
|
||||
&self.input_assignment,
|
||||
&self.aux_assignment
|
||||
&self.aux_assignment,
|
||||
)));
|
||||
}
|
||||
|
||||
fn push_namespace<NR, N>(&mut self, _: N)
|
||||
where NR: Into<String>, N: FnOnce() -> NR
|
||||
where
|
||||
NR: Into<String>,
|
||||
N: FnOnce() -> NR,
|
||||
{
|
||||
// Do nothing; we don't care about namespaces in this context.
|
||||
}
|
||||
|
||||
fn pop_namespace(&mut self)
|
||||
{
|
||||
fn pop_namespace(&mut self) {
|
||||
// Do nothing; we don't care about namespaces in this context.
|
||||
}
|
||||
|
||||
|
@ -187,9 +162,12 @@ impl<E: Engine> ConstraintSystem<E> for ProvingAssignment<E> {
|
|||
pub fn create_random_proof<E, C, R, P: ParameterSource<E>>(
|
||||
circuit: C,
|
||||
params: P,
|
||||
rng: &mut R
|
||||
rng: &mut R,
|
||||
) -> Result<Proof<E>, SynthesisError>
|
||||
where E: Engine, C: Circuit<E>, R: RngCore
|
||||
where
|
||||
E: Engine,
|
||||
C: Circuit<E>,
|
||||
R: RngCore,
|
||||
{
|
||||
let r = E::Fr::random(rng);
|
||||
let s = E::Fr::random(rng);
|
||||
|
@ -201,9 +179,11 @@ pub fn create_proof<E, C, P: ParameterSource<E>>(
|
|||
circuit: C,
|
||||
mut params: P,
|
||||
r: E::Fr,
|
||||
s: E::Fr
|
||||
s: E::Fr,
|
||||
) -> Result<Proof<E>, SynthesisError>
|
||||
where E: Engine, C: Circuit<E>
|
||||
where
|
||||
E: Engine,
|
||||
C: Circuit<E>,
|
||||
{
|
||||
let mut prover = ProvingAssignment {
|
||||
a_aux_density: DensityTracker::new(),
|
||||
|
@ -213,7 +193,7 @@ pub fn create_proof<E, C, P: ParameterSource<E>>(
|
|||
b: vec![],
|
||||
c: vec![],
|
||||
input_assignment: vec![],
|
||||
aux_assignment: vec![]
|
||||
aux_assignment: vec![],
|
||||
};
|
||||
|
||||
prover.alloc_input(|| "", || Ok(E::Fr::one()))?;
|
||||
|
@ -221,11 +201,7 @@ pub fn create_proof<E, C, P: ParameterSource<E>>(
|
|||
circuit.synthesize(&mut prover)?;
|
||||
|
||||
for i in 0..prover.input_assignment.len() {
|
||||
prover.enforce(|| "",
|
||||
|lc| lc + Variable(Index::Input(i)),
|
||||
|lc| lc,
|
||||
|lc| lc,
|
||||
);
|
||||
prover.enforce(|| "", |lc| lc + Variable(Index::Input(i)), |lc| lc, |lc| lc);
|
||||
}
|
||||
|
||||
let worker = Worker::new();
|
||||
|
@ -259,31 +235,76 @@ pub fn create_proof<E, C, P: ParameterSource<E>>(
|
|||
};
|
||||
|
||||
// TODO: parallelize if it's even helpful
|
||||
let input_assignment = Arc::new(prover.input_assignment.into_iter().map(|s| s.into_repr()).collect::<Vec<_>>());
|
||||
let aux_assignment = Arc::new(prover.aux_assignment.into_iter().map(|s| s.into_repr()).collect::<Vec<_>>());
|
||||
let input_assignment = Arc::new(
|
||||
prover
|
||||
.input_assignment
|
||||
.into_iter()
|
||||
.map(|s| s.into_repr())
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
let aux_assignment = Arc::new(
|
||||
prover
|
||||
.aux_assignment
|
||||
.into_iter()
|
||||
.map(|s| s.into_repr())
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
|
||||
let l = multiexp(&worker, params.get_l(aux_assignment.len())?, FullDensity, aux_assignment.clone());
|
||||
let l = multiexp(
|
||||
&worker,
|
||||
params.get_l(aux_assignment.len())?,
|
||||
FullDensity,
|
||||
aux_assignment.clone(),
|
||||
);
|
||||
|
||||
let a_aux_density_total = prover.a_aux_density.get_total_density();
|
||||
|
||||
let (a_inputs_source, a_aux_source) = params.get_a(input_assignment.len(), a_aux_density_total)?;
|
||||
let (a_inputs_source, a_aux_source) =
|
||||
params.get_a(input_assignment.len(), a_aux_density_total)?;
|
||||
|
||||
let a_inputs = multiexp(&worker, a_inputs_source, FullDensity, input_assignment.clone());
|
||||
let a_aux = multiexp(&worker, a_aux_source, Arc::new(prover.a_aux_density), aux_assignment.clone());
|
||||
let a_inputs = multiexp(
|
||||
&worker,
|
||||
a_inputs_source,
|
||||
FullDensity,
|
||||
input_assignment.clone(),
|
||||
);
|
||||
let a_aux = multiexp(
|
||||
&worker,
|
||||
a_aux_source,
|
||||
Arc::new(prover.a_aux_density),
|
||||
aux_assignment.clone(),
|
||||
);
|
||||
|
||||
let b_input_density = Arc::new(prover.b_input_density);
|
||||
let b_input_density_total = b_input_density.get_total_density();
|
||||
let b_aux_density = Arc::new(prover.b_aux_density);
|
||||
let b_aux_density_total = b_aux_density.get_total_density();
|
||||
|
||||
let (b_g1_inputs_source, b_g1_aux_source) = params.get_b_g1(b_input_density_total, b_aux_density_total)?;
|
||||
let (b_g1_inputs_source, b_g1_aux_source) =
|
||||
params.get_b_g1(b_input_density_total, b_aux_density_total)?;
|
||||
|
||||
let b_g1_inputs = multiexp(&worker, b_g1_inputs_source, b_input_density.clone(), input_assignment.clone());
|
||||
let b_g1_aux = multiexp(&worker, b_g1_aux_source, b_aux_density.clone(), aux_assignment.clone());
|
||||
let b_g1_inputs = multiexp(
|
||||
&worker,
|
||||
b_g1_inputs_source,
|
||||
b_input_density.clone(),
|
||||
input_assignment.clone(),
|
||||
);
|
||||
let b_g1_aux = multiexp(
|
||||
&worker,
|
||||
b_g1_aux_source,
|
||||
b_aux_density.clone(),
|
||||
aux_assignment.clone(),
|
||||
);
|
||||
|
||||
let (b_g2_inputs_source, b_g2_aux_source) = params.get_b_g2(b_input_density_total, b_aux_density_total)?;
|
||||
|
||||
let b_g2_inputs = multiexp(&worker, b_g2_inputs_source, b_input_density, input_assignment);
|
||||
let (b_g2_inputs_source, b_g2_aux_source) =
|
||||
params.get_b_g2(b_input_density_total, b_aux_density_total)?;
|
||||
|
||||
let b_g2_inputs = multiexp(
|
||||
&worker,
|
||||
b_g2_inputs_source,
|
||||
b_input_density,
|
||||
input_assignment,
|
||||
);
|
||||
let b_g2_aux = multiexp(&worker, b_g2_aux_source, b_aux_density, aux_assignment);
|
||||
|
||||
if vk.delta_g1.is_zero() || vk.delta_g2.is_zero() {
|
||||
|
@ -325,6 +346,6 @@ pub fn create_proof<E, C, P: ParameterSource<E>>(
|
|||
Ok(Proof {
|
||||
a: g_a.into_affine(),
|
||||
b: g_b.into_affine(),
|
||||
c: g_c.into_affine()
|
||||
c: g_c.into_affine(),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
use ff::{
|
||||
Field, LegendreSymbol, PrimeField, PrimeFieldDecodingError,
|
||||
PrimeFieldRepr, ScalarEngine, SqrtField};
|
||||
Field, LegendreSymbol, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, ScalarEngine,
|
||||
SqrtField,
|
||||
};
|
||||
use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
|
||||
use pairing::{Engine, PairingCurveAffine};
|
||||
|
||||
use rand_core::RngCore;
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
use rand_core::RngCore;
|
||||
use std::num::Wrapping;
|
||||
|
||||
const MODULUS_R: Wrapping<u32> = Wrapping(64513);
|
||||
|
@ -80,9 +81,13 @@ impl SqrtField for Fr {
|
|||
fn legendre(&self) -> LegendreSymbol {
|
||||
// s = self^((r - 1) // 2)
|
||||
let s = self.pow([32256]);
|
||||
if s == <Fr as Field>::zero() { LegendreSymbol::Zero }
|
||||
else if s == <Fr as Field>::one() { LegendreSymbol::QuadraticResidue }
|
||||
else { LegendreSymbol::QuadraticNonResidue }
|
||||
if s == <Fr as Field>::zero() {
|
||||
LegendreSymbol::Zero
|
||||
} else if s == <Fr as Field>::one() {
|
||||
LegendreSymbol::QuadraticResidue
|
||||
} else {
|
||||
LegendreSymbol::QuadraticNonResidue
|
||||
}
|
||||
}
|
||||
|
||||
fn sqrt(&self) -> Option<Self> {
|
||||
|
@ -100,7 +105,7 @@ impl SqrtField for Fr {
|
|||
let mut m = Fr::S;
|
||||
|
||||
while t != <Fr as Field>::one() {
|
||||
let mut i = 1;
|
||||
let mut i = 1;
|
||||
{
|
||||
let mut t2i = t;
|
||||
t2i.square();
|
||||
|
@ -258,15 +263,18 @@ impl Engine for DummyEngine {
|
|||
type G2Affine = Fr;
|
||||
type Fq = Fr;
|
||||
type Fqe = Fr;
|
||||
|
||||
|
||||
// TODO: This should be F_645131 or something. Doesn't matter for now.
|
||||
type Fqk = Fr;
|
||||
|
||||
fn miller_loop<'a, I>(i: I) -> Self::Fqk
|
||||
where I: IntoIterator<Item=&'a (
|
||||
&'a <Self::G1Affine as PairingCurveAffine>::Prepared,
|
||||
&'a <Self::G2Affine as PairingCurveAffine>::Prepared
|
||||
)>
|
||||
where
|
||||
I: IntoIterator<
|
||||
Item = &'a (
|
||||
&'a <Self::G1Affine as PairingCurveAffine>::Prepared,
|
||||
&'a <Self::G2Affine as PairingCurveAffine>::Prepared,
|
||||
),
|
||||
>,
|
||||
{
|
||||
let mut acc = <Fr as Field>::zero();
|
||||
|
||||
|
@ -280,8 +288,7 @@ impl Engine for DummyEngine {
|
|||
}
|
||||
|
||||
/// Perform final exponentiation of the result of a miller loop.
|
||||
fn final_exponentiation(this: &Self::Fqk) -> Option<Self::Fqk>
|
||||
{
|
||||
fn final_exponentiation(this: &Self::Fqk) -> Option<Self::Fqk> {
|
||||
Some(*this)
|
||||
}
|
||||
}
|
||||
|
@ -308,9 +315,7 @@ impl CurveProjective for Fr {
|
|||
<Fr as Field>::is_zero(self)
|
||||
}
|
||||
|
||||
fn batch_normalization(_: &mut [Self]) {
|
||||
|
||||
}
|
||||
fn batch_normalization(_: &mut [Self]) {}
|
||||
|
||||
fn is_normalized(&self) -> bool {
|
||||
true
|
||||
|
@ -332,8 +337,7 @@ impl CurveProjective for Fr {
|
|||
<Fr as Field>::negate(self);
|
||||
}
|
||||
|
||||
fn mul_assign<S: Into<<Self::Scalar as PrimeField>::Repr>>(&mut self, other: S)
|
||||
{
|
||||
fn mul_assign<S: Into<<Self::Scalar as PrimeField>::Repr>>(&mut self, other: S) {
|
||||
let tmp = Fr::from_repr(other.into()).unwrap();
|
||||
|
||||
<Fr as Field>::mul_assign(self, &tmp);
|
||||
|
@ -415,8 +419,7 @@ impl CurveAffine for Fr {
|
|||
<Fr as Field>::negate(self);
|
||||
}
|
||||
|
||||
fn mul<S: Into<<Self::Scalar as PrimeField>::Repr>>(&self, other: S) -> Self::Projective
|
||||
{
|
||||
fn mul<S: Into<<Self::Scalar as PrimeField>::Repr>>(&self, other: S) -> Self::Projective {
|
||||
let mut res = *self;
|
||||
let tmp = Fr::from_repr(other.into()).unwrap();
|
||||
|
||||
|
|
|
@ -6,86 +6,82 @@ use self::dummy_engine::*;
|
|||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use ::{
|
||||
Circuit,
|
||||
ConstraintSystem,
|
||||
SynthesisError
|
||||
};
|
||||
use {Circuit, ConstraintSystem, SynthesisError};
|
||||
|
||||
use super::{
|
||||
generate_parameters,
|
||||
prepare_verifying_key,
|
||||
create_proof,
|
||||
verify_proof
|
||||
};
|
||||
use super::{create_proof, generate_parameters, prepare_verifying_key, verify_proof};
|
||||
|
||||
struct XORDemo<E: Engine> {
|
||||
a: Option<bool>,
|
||||
b: Option<bool>,
|
||||
_marker: PhantomData<E>
|
||||
_marker: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<E: Engine> Circuit<E> for XORDemo<E> {
|
||||
fn synthesize<CS: ConstraintSystem<E>>(
|
||||
self,
|
||||
cs: &mut CS
|
||||
) -> Result<(), SynthesisError>
|
||||
{
|
||||
let a_var = cs.alloc(|| "a", || {
|
||||
if self.a.is_some() {
|
||||
if self.a.unwrap() {
|
||||
Ok(E::Fr::one())
|
||||
fn synthesize<CS: ConstraintSystem<E>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
|
||||
let a_var = cs.alloc(
|
||||
|| "a",
|
||||
|| {
|
||||
if self.a.is_some() {
|
||||
if self.a.unwrap() {
|
||||
Ok(E::Fr::one())
|
||||
} else {
|
||||
Ok(E::Fr::zero())
|
||||
}
|
||||
} else {
|
||||
Ok(E::Fr::zero())
|
||||
Err(SynthesisError::AssignmentMissing)
|
||||
}
|
||||
} else {
|
||||
Err(SynthesisError::AssignmentMissing)
|
||||
}
|
||||
})?;
|
||||
},
|
||||
)?;
|
||||
|
||||
cs.enforce(
|
||||
|| "a_boolean_constraint",
|
||||
|lc| lc + CS::one() - a_var,
|
||||
|lc| lc + a_var,
|
||||
|lc| lc
|
||||
|lc| lc,
|
||||
);
|
||||
|
||||
let b_var = cs.alloc(|| "b", || {
|
||||
if self.b.is_some() {
|
||||
if self.b.unwrap() {
|
||||
Ok(E::Fr::one())
|
||||
let b_var = cs.alloc(
|
||||
|| "b",
|
||||
|| {
|
||||
if self.b.is_some() {
|
||||
if self.b.unwrap() {
|
||||
Ok(E::Fr::one())
|
||||
} else {
|
||||
Ok(E::Fr::zero())
|
||||
}
|
||||
} else {
|
||||
Ok(E::Fr::zero())
|
||||
Err(SynthesisError::AssignmentMissing)
|
||||
}
|
||||
} else {
|
||||
Err(SynthesisError::AssignmentMissing)
|
||||
}
|
||||
})?;
|
||||
},
|
||||
)?;
|
||||
|
||||
cs.enforce(
|
||||
|| "b_boolean_constraint",
|
||||
|lc| lc + CS::one() - b_var,
|
||||
|lc| lc + b_var,
|
||||
|lc| lc
|
||||
|lc| lc,
|
||||
);
|
||||
|
||||
let c_var = cs.alloc_input(|| "c", || {
|
||||
if self.a.is_some() && self.b.is_some() {
|
||||
if self.a.unwrap() ^ self.b.unwrap() {
|
||||
Ok(E::Fr::one())
|
||||
let c_var = cs.alloc_input(
|
||||
|| "c",
|
||||
|| {
|
||||
if self.a.is_some() && self.b.is_some() {
|
||||
if self.a.unwrap() ^ self.b.unwrap() {
|
||||
Ok(E::Fr::one())
|
||||
} else {
|
||||
Ok(E::Fr::zero())
|
||||
}
|
||||
} else {
|
||||
Ok(E::Fr::zero())
|
||||
Err(SynthesisError::AssignmentMissing)
|
||||
}
|
||||
} else {
|
||||
Err(SynthesisError::AssignmentMissing)
|
||||
}
|
||||
})?;
|
||||
},
|
||||
)?;
|
||||
|
||||
cs.enforce(
|
||||
|| "c_xor_constraint",
|
||||
|lc| lc + a_var + a_var,
|
||||
|lc| lc + b_var,
|
||||
|lc| lc + a_var + b_var - c_var
|
||||
|lc| lc + a_var + b_var - c_var,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
@ -106,19 +102,10 @@ fn test_xordemo() {
|
|||
let c = XORDemo::<DummyEngine> {
|
||||
a: None,
|
||||
b: None,
|
||||
_marker: PhantomData
|
||||
_marker: PhantomData,
|
||||
};
|
||||
|
||||
generate_parameters(
|
||||
c,
|
||||
g1,
|
||||
g2,
|
||||
alpha,
|
||||
beta,
|
||||
gamma,
|
||||
delta,
|
||||
tau
|
||||
).unwrap()
|
||||
generate_parameters(c, g1, g2, alpha, beta, gamma, delta, tau).unwrap()
|
||||
};
|
||||
|
||||
// This will synthesize the constraint system:
|
||||
|
@ -226,32 +213,35 @@ fn test_xordemo() {
|
|||
59158
|
||||
*/
|
||||
|
||||
let u_i = [59158, 48317, 21767, 10402].iter().map(|e| {
|
||||
Fr::from_str(&format!("{}", e)).unwrap()
|
||||
}).collect::<Vec<Fr>>();
|
||||
let v_i = [0, 0, 60619, 30791].iter().map(|e| {
|
||||
Fr::from_str(&format!("{}", e)).unwrap()
|
||||
}).collect::<Vec<Fr>>();
|
||||
let w_i = [0, 23320, 41193, 41193].iter().map(|e| {
|
||||
Fr::from_str(&format!("{}", e)).unwrap()
|
||||
}).collect::<Vec<Fr>>();
|
||||
let u_i = [59158, 48317, 21767, 10402]
|
||||
.iter()
|
||||
.map(|e| Fr::from_str(&format!("{}", e)).unwrap())
|
||||
.collect::<Vec<Fr>>();
|
||||
let v_i = [0, 0, 60619, 30791]
|
||||
.iter()
|
||||
.map(|e| Fr::from_str(&format!("{}", e)).unwrap())
|
||||
.collect::<Vec<Fr>>();
|
||||
let w_i = [0, 23320, 41193, 41193]
|
||||
.iter()
|
||||
.map(|e| Fr::from_str(&format!("{}", e)).unwrap())
|
||||
.collect::<Vec<Fr>>();
|
||||
|
||||
for (u, a) in u_i.iter()
|
||||
.zip(¶ms.a[..])
|
||||
{
|
||||
for (u, a) in u_i.iter().zip(¶ms.a[..]) {
|
||||
assert_eq!(u, a);
|
||||
}
|
||||
|
||||
for (v, b) in v_i.iter()
|
||||
.filter(|&&e| e != Fr::zero())
|
||||
.zip(¶ms.b_g1[..])
|
||||
for (v, b) in v_i
|
||||
.iter()
|
||||
.filter(|&&e| e != Fr::zero())
|
||||
.zip(¶ms.b_g1[..])
|
||||
{
|
||||
assert_eq!(v, b);
|
||||
}
|
||||
|
||||
for (v, b) in v_i.iter()
|
||||
.filter(|&&e| e != Fr::zero())
|
||||
.zip(¶ms.b_g2[..])
|
||||
for (v, b) in v_i
|
||||
.iter()
|
||||
.filter(|&&e| e != Fr::zero())
|
||||
.zip(¶ms.b_g2[..])
|
||||
{
|
||||
assert_eq!(v, b);
|
||||
}
|
||||
|
@ -296,15 +286,10 @@ fn test_xordemo() {
|
|||
let c = XORDemo {
|
||||
a: Some(true),
|
||||
b: Some(false),
|
||||
_marker: PhantomData
|
||||
_marker: PhantomData,
|
||||
};
|
||||
|
||||
create_proof(
|
||||
c,
|
||||
¶ms,
|
||||
r,
|
||||
s
|
||||
).unwrap()
|
||||
create_proof(c, ¶ms, r, s).unwrap()
|
||||
};
|
||||
|
||||
// A(x) =
|
||||
|
@ -320,7 +305,7 @@ fn test_xordemo() {
|
|||
expected_a.add_assign(&u_i[0]); // a_0 = 1
|
||||
expected_a.add_assign(&u_i[1]); // a_1 = 1
|
||||
expected_a.add_assign(&u_i[2]); // a_2 = 1
|
||||
// a_3 = 0
|
||||
// a_3 = 0
|
||||
assert_eq!(proof.a, expected_a);
|
||||
}
|
||||
|
||||
|
@ -337,7 +322,7 @@ fn test_xordemo() {
|
|||
expected_b.add_assign(&v_i[0]); // a_0 = 1
|
||||
expected_b.add_assign(&v_i[1]); // a_1 = 1
|
||||
expected_b.add_assign(&v_i[2]); // a_2 = 1
|
||||
// a_3 = 0
|
||||
// a_3 = 0
|
||||
assert_eq!(proof.b, expected_b);
|
||||
}
|
||||
|
||||
|
@ -378,7 +363,10 @@ fn test_xordemo() {
|
|||
expected_c.add_assign(¶ms.l[0]);
|
||||
|
||||
// H query answer
|
||||
for (i, coeff) in [5040, 11763, 10755, 63633, 128, 9747, 8739].iter().enumerate() {
|
||||
for (i, coeff) in [5040, 11763, 10755, 63633, 128, 9747, 8739]
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
let coeff = Fr::from_str(&format!("{}", coeff)).unwrap();
|
||||
|
||||
let mut tmp = params.h[i];
|
||||
|
@ -389,9 +377,5 @@ fn test_xordemo() {
|
|||
assert_eq!(expected_c, proof.c);
|
||||
}
|
||||
|
||||
assert!(verify_proof(
|
||||
&pvk,
|
||||
&proof,
|
||||
&[Fr::one()]
|
||||
).unwrap());
|
||||
assert!(verify_proof(&pvk, &proof, &[Fr::one()]).unwrap());
|
||||
}
|
||||
|
|
|
@ -2,20 +2,11 @@ use ff::PrimeField;
|
|||
use group::{CurveAffine, CurveProjective};
|
||||
use pairing::{Engine, PairingCurveAffine};
|
||||
|
||||
use super::{
|
||||
Proof,
|
||||
VerifyingKey,
|
||||
PreparedVerifyingKey
|
||||
};
|
||||
use super::{PreparedVerifyingKey, Proof, VerifyingKey};
|
||||
|
||||
use ::{
|
||||
SynthesisError
|
||||
};
|
||||
use SynthesisError;
|
||||
|
||||
pub fn prepare_verifying_key<E: Engine>(
|
||||
vk: &VerifyingKey<E>
|
||||
) -> PreparedVerifyingKey<E>
|
||||
{
|
||||
pub fn prepare_verifying_key<E: Engine>(vk: &VerifyingKey<E>) -> PreparedVerifyingKey<E> {
|
||||
let mut gamma = vk.gamma_g2;
|
||||
gamma.negate();
|
||||
let mut delta = vk.delta_g2;
|
||||
|
@ -25,16 +16,15 @@ pub fn prepare_verifying_key<E: Engine>(
|
|||
alpha_g1_beta_g2: E::pairing(vk.alpha_g1, vk.beta_g2),
|
||||
neg_gamma_g2: gamma.prepare(),
|
||||
neg_delta_g2: delta.prepare(),
|
||||
ic: vk.ic.clone()
|
||||
ic: vk.ic.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verify_proof<'a, E: Engine>(
|
||||
pvk: &'a PreparedVerifyingKey<E>,
|
||||
proof: &Proof<E>,
|
||||
public_inputs: &[E::Fr]
|
||||
) -> Result<bool, SynthesisError>
|
||||
{
|
||||
public_inputs: &[E::Fr],
|
||||
) -> Result<bool, SynthesisError> {
|
||||
if (public_inputs.len() + 1) != pvk.ic.len() {
|
||||
return Err(SynthesisError::MalformedVerifyingKey);
|
||||
}
|
||||
|
@ -53,11 +43,14 @@ pub fn verify_proof<'a, E: Engine>(
|
|||
// A * B + inputs * (-gamma) + C * (-delta) = alpha * beta
|
||||
// which allows us to do a single final exponentiation.
|
||||
|
||||
Ok(E::final_exponentiation(
|
||||
&E::miller_loop([
|
||||
Ok(E::final_exponentiation(&E::miller_loop(
|
||||
[
|
||||
(&proof.a.prepare(), &proof.b.prepare()),
|
||||
(&acc.into_affine().prepare(), &pvk.neg_gamma_g2),
|
||||
(&proof.c.prepare(), &pvk.neg_delta_g2)
|
||||
].into_iter())
|
||||
).unwrap() == pvk.alpha_g1_beta_g2)
|
||||
(&proof.c.prepare(), &pvk.neg_delta_g2),
|
||||
]
|
||||
.into_iter(),
|
||||
))
|
||||
.unwrap()
|
||||
== pvk.alpha_g1_beta_g2)
|
||||
}
|
||||
|
|
180
src/lib.rs
180
src/lib.rs
|
@ -4,10 +4,10 @@ extern crate group;
|
|||
extern crate pairing;
|
||||
extern crate rand_core;
|
||||
|
||||
extern crate futures;
|
||||
extern crate bit_vec;
|
||||
extern crate blake2s_simd;
|
||||
extern crate byteorder;
|
||||
extern crate futures;
|
||||
|
||||
#[cfg(feature = "multicore")]
|
||||
extern crate crossbeam;
|
||||
|
@ -29,20 +29,20 @@ extern crate rand_xorshift;
|
|||
#[cfg(test)]
|
||||
extern crate sha2;
|
||||
|
||||
pub mod gadgets;
|
||||
pub mod multicore;
|
||||
mod multiexp;
|
||||
pub mod domain;
|
||||
pub mod gadgets;
|
||||
#[cfg(feature = "groth16")]
|
||||
pub mod groth16;
|
||||
pub mod multicore;
|
||||
mod multiexp;
|
||||
|
||||
use ff::{Field, ScalarEngine};
|
||||
|
||||
use std::ops::{Add, Sub};
|
||||
use std::fmt;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::{Add, Sub};
|
||||
|
||||
/// Computations are expressed in terms of arithmetic circuits, in particular
|
||||
/// rank-1 quadratic constraint systems. The `Circuit` trait represents a
|
||||
|
@ -50,10 +50,7 @@ use std::marker::PhantomData;
|
|||
/// CRS generation and during proving.
|
||||
pub trait Circuit<E: ScalarEngine> {
|
||||
/// Synthesize the circuit into a rank-1 quadratic constraint system
|
||||
fn synthesize<CS: ConstraintSystem<E>>(
|
||||
self,
|
||||
cs: &mut CS
|
||||
) -> Result<(), SynthesisError>;
|
||||
fn synthesize<CS: ConstraintSystem<E>>(self, cs: &mut CS) -> Result<(), SynthesisError>;
|
||||
}
|
||||
|
||||
/// Represents a variable in our constraint system.
|
||||
|
@ -79,7 +76,7 @@ impl Variable {
|
|||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub enum Index {
|
||||
Input(usize),
|
||||
Aux(usize)
|
||||
Aux(usize),
|
||||
}
|
||||
|
||||
/// This represents a linear combination of some variables, with coefficients
|
||||
|
@ -206,7 +203,7 @@ pub enum SynthesisError {
|
|||
/// During verification, our verifying key was malformed.
|
||||
MalformedVerifyingKey,
|
||||
/// During CRS generation, we observed an unconstrained auxiliary variable
|
||||
UnconstrainedVariable
|
||||
UnconstrainedVariable,
|
||||
}
|
||||
|
||||
impl From<io::Error> for SynthesisError {
|
||||
|
@ -218,14 +215,16 @@ impl From<io::Error> for SynthesisError {
|
|||
impl Error for SynthesisError {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
SynthesisError::AssignmentMissing => "an assignment for a variable could not be computed",
|
||||
SynthesisError::AssignmentMissing => {
|
||||
"an assignment for a variable could not be computed"
|
||||
}
|
||||
SynthesisError::DivisionByZero => "division by zero",
|
||||
SynthesisError::Unsatisfiable => "unsatisfiable constraint system",
|
||||
SynthesisError::PolynomialDegreeTooLarge => "polynomial degree is too large",
|
||||
SynthesisError::UnexpectedIdentity => "encountered an identity element in the CRS",
|
||||
SynthesisError::IoError(_) => "encountered an I/O error",
|
||||
SynthesisError::MalformedVerifyingKey => "malformed verifying key",
|
||||
SynthesisError::UnconstrainedVariable => "auxiliary variable was unconstrained"
|
||||
SynthesisError::UnconstrainedVariable => "auxiliary variable was unconstrained",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -257,40 +256,36 @@ pub trait ConstraintSystem<E: ScalarEngine>: Sized {
|
|||
/// determine the assignment of the variable. The given `annotation` function is invoked
|
||||
/// in testing contexts in order to derive a unique name for this variable in the current
|
||||
/// namespace.
|
||||
fn alloc<F, A, AR>(
|
||||
&mut self,
|
||||
annotation: A,
|
||||
f: F
|
||||
) -> Result<Variable, SynthesisError>
|
||||
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>;
|
||||
fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
|
||||
where
|
||||
F: FnOnce() -> Result<E::Fr, SynthesisError>,
|
||||
A: FnOnce() -> AR,
|
||||
AR: Into<String>;
|
||||
|
||||
/// Allocate a public variable in the constraint system. The provided function is used to
|
||||
/// determine the assignment of the variable.
|
||||
fn alloc_input<F, A, AR>(
|
||||
&mut self,
|
||||
annotation: A,
|
||||
f: F
|
||||
) -> Result<Variable, SynthesisError>
|
||||
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>;
|
||||
fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
|
||||
where
|
||||
F: FnOnce() -> Result<E::Fr, SynthesisError>,
|
||||
A: FnOnce() -> AR,
|
||||
AR: Into<String>;
|
||||
|
||||
/// Enforce that `A` * `B` = `C`. The `annotation` function is invoked in testing contexts
|
||||
/// in order to derive a unique name for the constraint in the current namespace.
|
||||
fn enforce<A, AR, LA, LB, LC>(
|
||||
&mut self,
|
||||
annotation: 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>;
|
||||
fn enforce<A, AR, LA, LB, LC>(&mut self, annotation: 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>;
|
||||
|
||||
/// Create a new (sub)namespace and enter into it. Not intended
|
||||
/// for downstream use; use `namespace` instead.
|
||||
fn push_namespace<NR, N>(&mut self, name_fn: N)
|
||||
where NR: Into<String>, N: FnOnce() -> NR;
|
||||
where
|
||||
NR: Into<String>,
|
||||
N: FnOnce() -> NR;
|
||||
|
||||
/// Exit out of the existing namespace. Not intended for
|
||||
/// downstream use; use `namespace` instead.
|
||||
|
@ -301,11 +296,10 @@ pub trait ConstraintSystem<E: ScalarEngine>: Sized {
|
|||
fn get_root(&mut self) -> &mut Self::Root;
|
||||
|
||||
/// Begin a namespace for this constraint system.
|
||||
fn namespace<'a, NR, N>(
|
||||
&'a mut self,
|
||||
name_fn: N
|
||||
) -> Namespace<'a, E, Self::Root>
|
||||
where NR: Into<String>, N: FnOnce() -> NR
|
||||
fn namespace<'a, NR, N>(&'a mut self, name_fn: N) -> Namespace<'a, E, Self::Root>
|
||||
where
|
||||
NR: Into<String>,
|
||||
N: FnOnce() -> NR,
|
||||
{
|
||||
self.get_root().push_namespace(name_fn);
|
||||
|
||||
|
@ -324,37 +318,31 @@ impl<'cs, E: ScalarEngine, CS: ConstraintSystem<E>> ConstraintSystem<E> for Name
|
|||
CS::one()
|
||||
}
|
||||
|
||||
fn alloc<F, A, AR>(
|
||||
&mut self,
|
||||
annotation: A,
|
||||
f: F
|
||||
) -> Result<Variable, SynthesisError>
|
||||
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
|
||||
fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
|
||||
where
|
||||
F: FnOnce() -> Result<E::Fr, SynthesisError>,
|
||||
A: FnOnce() -> AR,
|
||||
AR: Into<String>,
|
||||
{
|
||||
self.0.alloc(annotation, f)
|
||||
}
|
||||
|
||||
fn alloc_input<F, A, AR>(
|
||||
&mut self,
|
||||
annotation: A,
|
||||
f: F
|
||||
) -> Result<Variable, SynthesisError>
|
||||
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
|
||||
fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
|
||||
where
|
||||
F: FnOnce() -> Result<E::Fr, SynthesisError>,
|
||||
A: FnOnce() -> AR,
|
||||
AR: Into<String>,
|
||||
{
|
||||
self.0.alloc_input(annotation, f)
|
||||
}
|
||||
|
||||
fn enforce<A, AR, LA, LB, LC>(
|
||||
&mut self,
|
||||
annotation: 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>
|
||||
fn enforce<A, AR, LA, LB, LC>(&mut self, annotation: 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>,
|
||||
{
|
||||
self.0.enforce(annotation, a, b, c)
|
||||
}
|
||||
|
@ -364,18 +352,18 @@ impl<'cs, E: ScalarEngine, CS: ConstraintSystem<E>> ConstraintSystem<E> for Name
|
|||
// never a root constraint system.
|
||||
|
||||
fn push_namespace<NR, N>(&mut self, _: N)
|
||||
where NR: Into<String>, N: FnOnce() -> NR
|
||||
where
|
||||
NR: Into<String>,
|
||||
N: FnOnce() -> NR,
|
||||
{
|
||||
panic!("only the root's push_namespace should be called");
|
||||
}
|
||||
|
||||
fn pop_namespace(&mut self)
|
||||
{
|
||||
fn pop_namespace(&mut self) {
|
||||
panic!("only the root's pop_namespace should be called");
|
||||
}
|
||||
|
||||
fn get_root(&mut self) -> &mut Self::Root
|
||||
{
|
||||
fn get_root(&mut self) -> &mut Self::Root {
|
||||
self.0.get_root()
|
||||
}
|
||||
}
|
||||
|
@ -395,54 +383,48 @@ impl<'cs, E: ScalarEngine, CS: ConstraintSystem<E>> ConstraintSystem<E> for &'cs
|
|||
CS::one()
|
||||
}
|
||||
|
||||
fn alloc<F, A, AR>(
|
||||
&mut self,
|
||||
annotation: A,
|
||||
f: F
|
||||
) -> Result<Variable, SynthesisError>
|
||||
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
|
||||
fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
|
||||
where
|
||||
F: FnOnce() -> Result<E::Fr, SynthesisError>,
|
||||
A: FnOnce() -> AR,
|
||||
AR: Into<String>,
|
||||
{
|
||||
(**self).alloc(annotation, f)
|
||||
}
|
||||
|
||||
fn alloc_input<F, A, AR>(
|
||||
&mut self,
|
||||
annotation: A,
|
||||
f: F
|
||||
) -> Result<Variable, SynthesisError>
|
||||
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
|
||||
fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
|
||||
where
|
||||
F: FnOnce() -> Result<E::Fr, SynthesisError>,
|
||||
A: FnOnce() -> AR,
|
||||
AR: Into<String>,
|
||||
{
|
||||
(**self).alloc_input(annotation, f)
|
||||
}
|
||||
|
||||
fn enforce<A, AR, LA, LB, LC>(
|
||||
&mut self,
|
||||
annotation: 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>
|
||||
fn enforce<A, AR, LA, LB, LC>(&mut self, annotation: 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>,
|
||||
{
|
||||
(**self).enforce(annotation, a, b, c)
|
||||
}
|
||||
|
||||
fn push_namespace<NR, N>(&mut self, name_fn: N)
|
||||
where NR: Into<String>, N: FnOnce() -> NR
|
||||
where
|
||||
NR: Into<String>,
|
||||
N: FnOnce() -> NR,
|
||||
{
|
||||
(**self).push_namespace(name_fn)
|
||||
}
|
||||
|
||||
fn pop_namespace(&mut self)
|
||||
{
|
||||
fn pop_namespace(&mut self) {
|
||||
(**self).pop_namespace()
|
||||
}
|
||||
|
||||
fn get_root(&mut self) -> &mut Self::Root
|
||||
{
|
||||
fn get_root(&mut self) -> &mut Self::Root {
|
||||
(**self).get_root()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,15 +6,15 @@
|
|||
|
||||
#[cfg(feature = "multicore")]
|
||||
mod implementation {
|
||||
use num_cpus;
|
||||
use futures::{Future, IntoFuture, Poll};
|
||||
use futures_cpupool::{CpuPool, CpuFuture};
|
||||
use crossbeam::{self, Scope};
|
||||
use futures::{Future, IntoFuture, Poll};
|
||||
use futures_cpupool::{CpuFuture, CpuPool};
|
||||
use num_cpus;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Worker {
|
||||
cpus: usize,
|
||||
pool: CpuPool
|
||||
pool: CpuPool,
|
||||
}
|
||||
|
||||
impl Worker {
|
||||
|
@ -24,7 +24,7 @@ mod implementation {
|
|||
pub(crate) fn new_with_cpus(cpus: usize) -> Worker {
|
||||
Worker {
|
||||
cpus: cpus,
|
||||
pool: CpuPool::new(cpus)
|
||||
pool: CpuPool::new(cpus),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,26 +36,22 @@ mod implementation {
|
|||
log2_floor(self.cpus)
|
||||
}
|
||||
|
||||
pub fn compute<F, R>(
|
||||
&self, f: F
|
||||
) -> WorkerFuture<R::Item, R::Error>
|
||||
where F: FnOnce() -> R + Send + 'static,
|
||||
R: IntoFuture + 'static,
|
||||
R::Future: Send + 'static,
|
||||
R::Item: Send + 'static,
|
||||
R::Error: Send + 'static
|
||||
pub fn compute<F, R>(&self, f: F) -> WorkerFuture<R::Item, R::Error>
|
||||
where
|
||||
F: FnOnce() -> R + Send + 'static,
|
||||
R: IntoFuture + 'static,
|
||||
R::Future: Send + 'static,
|
||||
R::Item: Send + 'static,
|
||||
R::Error: Send + 'static,
|
||||
{
|
||||
WorkerFuture {
|
||||
future: self.pool.spawn_fn(f)
|
||||
future: self.pool.spawn_fn(f),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scope<'a, F, R>(
|
||||
&self,
|
||||
elements: usize,
|
||||
f: F
|
||||
) -> R
|
||||
where F: FnOnce(&Scope<'a>, usize) -> R
|
||||
pub fn scope<'a, F, R>(&self, elements: usize, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&Scope<'a>, usize) -> R,
|
||||
{
|
||||
let chunk_size = if elements < self.cpus {
|
||||
1
|
||||
|
@ -63,22 +59,19 @@ mod implementation {
|
|||
elements / self.cpus
|
||||
};
|
||||
|
||||
crossbeam::scope(|scope| {
|
||||
f(scope, chunk_size)
|
||||
})
|
||||
crossbeam::scope(|scope| f(scope, chunk_size))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WorkerFuture<T, E> {
|
||||
future: CpuFuture<T, E>
|
||||
future: CpuFuture<T, E>,
|
||||
}
|
||||
|
||||
impl<T: Send + 'static, E: Send + 'static> Future for WorkerFuture<T, E> {
|
||||
type Item = T;
|
||||
type Error = E;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error>
|
||||
{
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
self.future.poll()
|
||||
}
|
||||
}
|
||||
|
@ -88,7 +81,7 @@ mod implementation {
|
|||
|
||||
let mut pow = 0;
|
||||
|
||||
while (1 << (pow+1)) <= num {
|
||||
while (1 << (pow + 1)) <= num {
|
||||
pow += 1;
|
||||
}
|
||||
|
||||
|
|
120
src/multiexp.rs
120
src/multiexp.rs
|
@ -1,11 +1,11 @@
|
|||
use ff::{Field, PrimeField, PrimeFieldRepr, ScalarEngine};
|
||||
use group::{CurveAffine, CurveProjective};
|
||||
use std::sync::Arc;
|
||||
use std::io;
|
||||
use bit_vec::{self, BitVec};
|
||||
use std::iter;
|
||||
use futures::{Future};
|
||||
use super::multicore::Worker;
|
||||
use bit_vec::{self, BitVec};
|
||||
use ff::{Field, PrimeField, PrimeFieldRepr, ScalarEngine};
|
||||
use futures::Future;
|
||||
use group::{CurveAffine, CurveProjective};
|
||||
use std::io;
|
||||
use std::iter;
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::SynthesisError;
|
||||
|
||||
|
@ -19,7 +19,10 @@ pub trait SourceBuilder<G: CurveAffine>: Send + Sync + 'static + Clone {
|
|||
/// A source of bases, like an iterator.
|
||||
pub trait Source<G: CurveAffine> {
|
||||
/// Parses the element from the source. Fails if the point is at infinity.
|
||||
fn add_assign_mixed(&mut self, to: &mut <G as CurveAffine>::Projective) -> Result<(), SynthesisError>;
|
||||
fn add_assign_mixed(
|
||||
&mut self,
|
||||
to: &mut <G as CurveAffine>::Projective,
|
||||
) -> Result<(), SynthesisError>;
|
||||
|
||||
/// Skips `amt` elements from the source, avoiding deserialization.
|
||||
fn skip(&mut self, amt: usize) -> Result<(), SynthesisError>;
|
||||
|
@ -34,13 +37,20 @@ impl<G: CurveAffine> SourceBuilder<G> for (Arc<Vec<G>>, usize) {
|
|||
}
|
||||
|
||||
impl<G: CurveAffine> Source<G> for (Arc<Vec<G>>, usize) {
|
||||
fn add_assign_mixed(&mut self, to: &mut <G as CurveAffine>::Projective) -> Result<(), SynthesisError> {
|
||||
fn add_assign_mixed(
|
||||
&mut self,
|
||||
to: &mut <G as CurveAffine>::Projective,
|
||||
) -> Result<(), SynthesisError> {
|
||||
if self.0.len() <= self.1 {
|
||||
return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "expected more bases from source").into());
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::UnexpectedEof,
|
||||
"expected more bases from source",
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
if self.0[self.1].is_zero() {
|
||||
return Err(SynthesisError::UnexpectedIdentity)
|
||||
return Err(SynthesisError::UnexpectedIdentity);
|
||||
}
|
||||
|
||||
to.add_assign_mixed(&self.0[self.1]);
|
||||
|
@ -52,7 +62,11 @@ impl<G: CurveAffine> Source<G> for (Arc<Vec<G>>, usize) {
|
|||
|
||||
fn skip(&mut self, amt: usize) -> Result<(), SynthesisError> {
|
||||
if self.0.len() <= self.1 {
|
||||
return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "expected more bases from source").into());
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::UnexpectedEof,
|
||||
"expected more bases from source",
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
self.1 += amt;
|
||||
|
@ -63,7 +77,7 @@ impl<G: CurveAffine> Source<G> for (Arc<Vec<G>>, usize) {
|
|||
|
||||
pub trait QueryDensity {
|
||||
/// Returns whether the base exists.
|
||||
type Iter: Iterator<Item=bool>;
|
||||
type Iter: Iterator<Item = bool>;
|
||||
|
||||
fn iter(self) -> Self::Iter;
|
||||
fn get_query_size(self) -> Option<usize>;
|
||||
|
@ -92,7 +106,7 @@ impl<'a> QueryDensity for &'a FullDensity {
|
|||
|
||||
pub struct DensityTracker {
|
||||
bv: BitVec,
|
||||
total_density: usize
|
||||
total_density: usize,
|
||||
}
|
||||
|
||||
impl<'a> QueryDensity for &'a DensityTracker {
|
||||
|
@ -111,7 +125,7 @@ impl DensityTracker {
|
|||
pub fn new() -> DensityTracker {
|
||||
DensityTracker {
|
||||
bv: BitVec::new(),
|
||||
total_density: 0
|
||||
total_density: 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,12 +152,13 @@ fn multiexp_inner<Q, D, G, S>(
|
|||
exponents: Arc<Vec<<<G::Engine as ScalarEngine>::Fr as PrimeField>::Repr>>,
|
||||
mut skip: u32,
|
||||
c: u32,
|
||||
handle_trivial: bool
|
||||
) -> Box<Future<Item=<G as CurveAffine>::Projective, Error=SynthesisError>>
|
||||
where for<'a> &'a Q: QueryDensity,
|
||||
D: Send + Sync + 'static + Clone + AsRef<Q>,
|
||||
G: CurveAffine,
|
||||
S: SourceBuilder<G>
|
||||
handle_trivial: bool,
|
||||
) -> Box<Future<Item = <G as CurveAffine>::Projective, Error = SynthesisError>>
|
||||
where
|
||||
for<'a> &'a Q: QueryDensity,
|
||||
D: Send + Sync + 'static + Clone + AsRef<Q>,
|
||||
G: CurveAffine,
|
||||
S: SourceBuilder<G>,
|
||||
{
|
||||
// Perform this region of the multiexp
|
||||
let this = {
|
||||
|
@ -212,16 +227,24 @@ fn multiexp_inner<Q, D, G, S>(
|
|||
// There's another region more significant. Calculate and join it with
|
||||
// this region recursively.
|
||||
Box::new(
|
||||
this.join(multiexp_inner(pool, bases, density_map, exponents, skip, c, false))
|
||||
.map(move |(this, mut higher)| {
|
||||
for _ in 0..c {
|
||||
higher.double();
|
||||
}
|
||||
this.join(multiexp_inner(
|
||||
pool,
|
||||
bases,
|
||||
density_map,
|
||||
exponents,
|
||||
skip,
|
||||
c,
|
||||
false,
|
||||
))
|
||||
.map(move |(this, mut higher)| {
|
||||
for _ in 0..c {
|
||||
higher.double();
|
||||
}
|
||||
|
||||
higher.add_assign(&this);
|
||||
higher.add_assign(&this);
|
||||
|
||||
higher
|
||||
})
|
||||
higher
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -232,12 +255,13 @@ pub fn multiexp<Q, D, G, S>(
|
|||
pool: &Worker,
|
||||
bases: S,
|
||||
density_map: D,
|
||||
exponents: Arc<Vec<<<G::Engine as ScalarEngine>::Fr as PrimeField>::Repr>>
|
||||
) -> Box<Future<Item=<G as CurveAffine>::Projective, Error=SynthesisError>>
|
||||
where for<'a> &'a Q: QueryDensity,
|
||||
D: Send + Sync + 'static + Clone + AsRef<Q>,
|
||||
G: CurveAffine,
|
||||
S: SourceBuilder<G>
|
||||
exponents: Arc<Vec<<<G::Engine as ScalarEngine>::Fr as PrimeField>::Repr>>,
|
||||
) -> Box<Future<Item = <G as CurveAffine>::Projective, Error = SynthesisError>>
|
||||
where
|
||||
for<'a> &'a Q: QueryDensity,
|
||||
D: Send + Sync + 'static + Clone + AsRef<Q>,
|
||||
G: CurveAffine,
|
||||
S: SourceBuilder<G>,
|
||||
{
|
||||
let c = if exponents.len() < 32 {
|
||||
3u32
|
||||
|
@ -260,9 +284,8 @@ pub fn multiexp<Q, D, G, S>(
|
|||
fn test_with_bls12() {
|
||||
fn naive_multiexp<G: CurveAffine>(
|
||||
bases: Arc<Vec<G>>,
|
||||
exponents: Arc<Vec<<G::Scalar as PrimeField>::Repr>>
|
||||
) -> G::Projective
|
||||
{
|
||||
exponents: Arc<Vec<<G::Scalar as PrimeField>::Repr>>,
|
||||
) -> G::Projective {
|
||||
assert_eq!(bases.len(), exponents.len());
|
||||
|
||||
let mut acc = G::Projective::zero();
|
||||
|
@ -274,25 +297,28 @@ fn test_with_bls12() {
|
|||
acc
|
||||
}
|
||||
|
||||
use rand;
|
||||
use pairing::{bls12_381::Bls12, Engine};
|
||||
use rand;
|
||||
|
||||
const SAMPLES: usize = 1 << 14;
|
||||
|
||||
let rng = &mut rand::thread_rng();
|
||||
let v = Arc::new((0..SAMPLES).map(|_| <Bls12 as ScalarEngine>::Fr::random(rng).into_repr()).collect::<Vec<_>>());
|
||||
let g = Arc::new((0..SAMPLES).map(|_| <Bls12 as Engine>::G1::random(rng).into_affine()).collect::<Vec<_>>());
|
||||
let v = Arc::new(
|
||||
(0..SAMPLES)
|
||||
.map(|_| <Bls12 as ScalarEngine>::Fr::random(rng).into_repr())
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
let g = Arc::new(
|
||||
(0..SAMPLES)
|
||||
.map(|_| <Bls12 as Engine>::G1::random(rng).into_affine())
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
|
||||
let naive = naive_multiexp(g.clone(), v.clone());
|
||||
|
||||
let pool = Worker::new();
|
||||
|
||||
let fast = multiexp(
|
||||
&pool,
|
||||
(g, 0),
|
||||
FullDensity,
|
||||
v
|
||||
).wait().unwrap();
|
||||
let fast = multiexp(&pool, (g, 0), FullDensity, v).wait().unwrap();
|
||||
|
||||
assert_eq!(naive, fast);
|
||||
}
|
||||
|
|
|
@ -14,31 +14,21 @@ use ff::{Field, ScalarEngine};
|
|||
use pairing::Engine;
|
||||
|
||||
// We're going to use the BLS12-381 pairing-friendly elliptic curve.
|
||||
use pairing::bls12_381::{
|
||||
Bls12
|
||||
};
|
||||
use pairing::bls12_381::Bls12;
|
||||
|
||||
// We'll use these interfaces to construct our circuit.
|
||||
use bellman::{
|
||||
Circuit,
|
||||
ConstraintSystem,
|
||||
SynthesisError
|
||||
};
|
||||
use bellman::{Circuit, ConstraintSystem, SynthesisError};
|
||||
|
||||
// We're going to use the Groth16 proving system.
|
||||
use bellman::groth16::{
|
||||
Proof,
|
||||
generate_random_parameters,
|
||||
prepare_verifying_key,
|
||||
create_random_proof,
|
||||
verify_proof,
|
||||
create_random_proof, generate_random_parameters, prepare_verifying_key, verify_proof, Proof,
|
||||
};
|
||||
|
||||
const MIMC_ROUNDS: usize = 322;
|
||||
|
||||
/// This is an implementation of MiMC, specifically a
|
||||
/// variant named `LongsightF322p3` for BLS12-381.
|
||||
/// See http://eprint.iacr.org/2016/492 for more
|
||||
/// See http://eprint.iacr.org/2016/492 for more
|
||||
/// information about this construction.
|
||||
///
|
||||
/// ```
|
||||
|
@ -49,12 +39,7 @@ const MIMC_ROUNDS: usize = 322;
|
|||
/// return xL
|
||||
/// }
|
||||
/// ```
|
||||
fn mimc<E: Engine>(
|
||||
mut xl: E::Fr,
|
||||
mut xr: E::Fr,
|
||||
constants: &[E::Fr]
|
||||
) -> E::Fr
|
||||
{
|
||||
fn mimc<E: Engine>(mut xl: E::Fr, mut xr: E::Fr, constants: &[E::Fr]) -> E::Fr {
|
||||
assert_eq!(constants.len(), MIMC_ROUNDS);
|
||||
|
||||
for i in 0..MIMC_ROUNDS {
|
||||
|
@ -76,31 +61,29 @@ fn mimc<E: Engine>(
|
|||
struct MiMCDemo<'a, E: Engine> {
|
||||
xl: Option<E::Fr>,
|
||||
xr: Option<E::Fr>,
|
||||
constants: &'a [E::Fr]
|
||||
constants: &'a [E::Fr],
|
||||
}
|
||||
|
||||
/// Our demo circuit implements this `Circuit` trait which
|
||||
/// is used during paramgen and proving in order to
|
||||
/// synthesize the constraint system.
|
||||
impl<'a, E: Engine> Circuit<E> for MiMCDemo<'a, E> {
|
||||
fn synthesize<CS: ConstraintSystem<E>>(
|
||||
self,
|
||||
cs: &mut CS
|
||||
) -> Result<(), SynthesisError>
|
||||
{
|
||||
fn synthesize<CS: ConstraintSystem<E>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
|
||||
assert_eq!(self.constants.len(), MIMC_ROUNDS);
|
||||
|
||||
// Allocate the first component of the preimage.
|
||||
let mut xl_value = self.xl;
|
||||
let mut xl = cs.alloc(|| "preimage xl", || {
|
||||
xl_value.ok_or(SynthesisError::AssignmentMissing)
|
||||
})?;
|
||||
let mut xl = cs.alloc(
|
||||
|| "preimage xl",
|
||||
|| xl_value.ok_or(SynthesisError::AssignmentMissing),
|
||||
)?;
|
||||
|
||||
// Allocate the second component of the preimage.
|
||||
let mut xr_value = self.xr;
|
||||
let mut xr = cs.alloc(|| "preimage xr", || {
|
||||
xr_value.ok_or(SynthesisError::AssignmentMissing)
|
||||
})?;
|
||||
let mut xr = cs.alloc(
|
||||
|| "preimage xr",
|
||||
|| xr_value.ok_or(SynthesisError::AssignmentMissing),
|
||||
)?;
|
||||
|
||||
for i in 0..MIMC_ROUNDS {
|
||||
// xL, xR := xR + (xL + Ci)^3, xL
|
||||
|
@ -112,15 +95,16 @@ impl<'a, E: Engine> Circuit<E> for MiMCDemo<'a, E> {
|
|||
e.square();
|
||||
e
|
||||
});
|
||||
let mut tmp = cs.alloc(|| "tmp", || {
|
||||
tmp_value.ok_or(SynthesisError::AssignmentMissing)
|
||||
})?;
|
||||
let mut tmp = cs.alloc(
|
||||
|| "tmp",
|
||||
|| tmp_value.ok_or(SynthesisError::AssignmentMissing),
|
||||
)?;
|
||||
|
||||
cs.enforce(
|
||||
|| "tmp = (xL + Ci)^2",
|
||||
|lc| lc + xl + (self.constants[i], CS::one()),
|
||||
|lc| lc + xl + (self.constants[i], CS::one()),
|
||||
|lc| lc + tmp
|
||||
|lc| lc + tmp,
|
||||
);
|
||||
|
||||
// new_xL = xR + (xL + Ci)^3
|
||||
|
@ -133,23 +117,25 @@ impl<'a, E: Engine> Circuit<E> for MiMCDemo<'a, E> {
|
|||
e
|
||||
});
|
||||
|
||||
let mut new_xl = if i == (MIMC_ROUNDS-1) {
|
||||
let mut new_xl = if i == (MIMC_ROUNDS - 1) {
|
||||
// This is the last round, xL is our image and so
|
||||
// we allocate a public input.
|
||||
cs.alloc_input(|| "image", || {
|
||||
new_xl_value.ok_or(SynthesisError::AssignmentMissing)
|
||||
})?
|
||||
cs.alloc_input(
|
||||
|| "image",
|
||||
|| new_xl_value.ok_or(SynthesisError::AssignmentMissing),
|
||||
)?
|
||||
} else {
|
||||
cs.alloc(|| "new_xl", || {
|
||||
new_xl_value.ok_or(SynthesisError::AssignmentMissing)
|
||||
})?
|
||||
cs.alloc(
|
||||
|| "new_xl",
|
||||
|| new_xl_value.ok_or(SynthesisError::AssignmentMissing),
|
||||
)?
|
||||
};
|
||||
|
||||
cs.enforce(
|
||||
|| "new_xL = xR + (xL + Ci)^3",
|
||||
|lc| lc + tmp,
|
||||
|lc| lc + xl + (self.constants[i], CS::one()),
|
||||
|lc| lc + new_xl - xr
|
||||
|lc| lc + new_xl - xr,
|
||||
);
|
||||
|
||||
// xR = xL
|
||||
|
@ -172,7 +158,9 @@ fn test_mimc() {
|
|||
let rng = &mut thread_rng();
|
||||
|
||||
// Generate the MiMC round constants
|
||||
let constants = (0..MIMC_ROUNDS).map(|_| <Bls12 as ScalarEngine>::Fr::random(rng)).collect::<Vec<_>>();
|
||||
let constants = (0..MIMC_ROUNDS)
|
||||
.map(|_| <Bls12 as ScalarEngine>::Fr::random(rng))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
println!("Creating parameters...");
|
||||
|
||||
|
@ -181,7 +169,7 @@ fn test_mimc() {
|
|||
let c = MiMCDemo::<Bls12> {
|
||||
xl: None,
|
||||
xr: None,
|
||||
constants: &constants
|
||||
constants: &constants,
|
||||
};
|
||||
|
||||
generate_random_parameters(c, rng).unwrap()
|
||||
|
@ -216,7 +204,7 @@ fn test_mimc() {
|
|||
let c = MiMCDemo {
|
||||
xl: Some(xl),
|
||||
xr: Some(xr),
|
||||
constants: &constants
|
||||
constants: &constants,
|
||||
};
|
||||
|
||||
// Create a groth16 proof with our parameters.
|
||||
|
@ -230,20 +218,16 @@ fn test_mimc() {
|
|||
let start = Instant::now();
|
||||
let proof = Proof::read(&proof_vec[..]).unwrap();
|
||||
// Check the proof
|
||||
assert!(verify_proof(
|
||||
&pvk,
|
||||
&proof,
|
||||
&[image]
|
||||
).unwrap());
|
||||
assert!(verify_proof(&pvk, &proof, &[image]).unwrap());
|
||||
total_verifying += start.elapsed();
|
||||
}
|
||||
let proving_avg = total_proving / SAMPLES;
|
||||
let proving_avg = proving_avg.subsec_nanos() as f64 / 1_000_000_000f64
|
||||
+ (proving_avg.as_secs() as f64);
|
||||
let proving_avg =
|
||||
proving_avg.subsec_nanos() as f64 / 1_000_000_000f64 + (proving_avg.as_secs() as f64);
|
||||
|
||||
let verifying_avg = total_verifying / SAMPLES;
|
||||
let verifying_avg = verifying_avg.subsec_nanos() as f64 / 1_000_000_000f64
|
||||
+ (verifying_avg.as_secs() as f64);
|
||||
let verifying_avg =
|
||||
verifying_avg.subsec_nanos() as f64 / 1_000_000_000f64 + (verifying_avg.as_secs() as f64);
|
||||
|
||||
println!("Average proving time: {:?} seconds", proving_avg);
|
||||
println!("Average verifying time: {:?} seconds", verifying_avg);
|
||||
|
|
Loading…
Reference in New Issue