Skip to content

Commit

Permalink
Add common mimc test utils
Browse files Browse the repository at this point in the history
  • Loading branch information
dconnolly committed Feb 1, 2021
1 parent 414c4f2 commit b750faa
Showing 1 changed file with 128 additions and 0 deletions.
128 changes: 128 additions & 0 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
use ff::PrimeField;

use bellman::{Circuit, ConstraintSystem, SynthesisError};

pub 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
/// information about this construction.
///
/// ```
/// function LongsightF322p3(xL ⦂ Fp, xR ⦂ Fp) {
/// for i from 0 up to 321 {
/// xL, xR := xR + (xL + Ci)^3, xL
/// }
/// return xL
/// }
/// ```
pub fn mimc<S: PrimeField>(mut xl: S, mut xr: S, constants: &[S]) -> S {
assert_eq!(constants.len(), MIMC_ROUNDS);

for c in constants {
let mut tmp1 = xl;
tmp1.add_assign(c);
let mut tmp2 = tmp1.square();
tmp2.mul_assign(&tmp1);
tmp2.add_assign(&xr);
xr = xl;
xl = tmp2;
}

xl
}

/// This is our demo circuit for proving knowledge of the
/// preimage of a MiMC hash invocation.
pub struct MiMCDemo<'a, S: PrimeField> {
pub xl: Option<S>,
pub xr: Option<S>,
pub constants: &'a [S],
}

/// Our demo circuit implements this `Circuit` trait which
/// is used during paramgen and proving in order to
/// synthesize the constraint system.
impl<'a, S: PrimeField> Circuit<S> for MiMCDemo<'a, S> {
fn synthesize<CS: ConstraintSystem<S>>(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),
)?;

// 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),
)?;

for i in 0..MIMC_ROUNDS {
// xL, xR := xR + (xL + Ci)^3, xL
let cs = &mut cs.namespace(|| format!("round {}", i));

// tmp = (xL + Ci)^2
let tmp_value = xl_value.map(|mut e| {
e.add_assign(&self.constants[i]);
e.square()
});
let 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,
);

// new_xL = xR + (xL + Ci)^3
// new_xL = xR + tmp * (xL + Ci)
// new_xL - xR = tmp * (xL + Ci)
let new_xl_value = xl_value.map(|mut e| {
e.add_assign(&self.constants[i]);
e.mul_assign(&tmp_value.unwrap());
e.add_assign(&xr_value.unwrap());
e
});

let 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),
)?
} else {
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,
);

// xR = xL
xr = xl;
xr_value = xl_value;

// xL = new_xL
xl = new_xl;
xl_value = new_xl_value;
}

Ok(())
}
}

0 comments on commit b750faa

Please sign in to comment.