use bellperson::bls::Engine; use bellperson::{Circuit, ConstraintSystem, SynthesisError}; use fff::Field; pub const MIMC_ROUNDS: usize = 322; pub fn mimc(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 { let mut tmp1 = xl; tmp1.add_assign(&constants[i]); let mut tmp2 = tmp1; tmp2.square(); tmp2.mul_assign(&tmp1); tmp2.add_assign(&xr); xr = xl; xl = tmp2; } xl } pub struct MiMCDemo<'a, E: Engine> { pub xl: Option, pub xr: Option, pub constants: &'a [E::Fr], } impl<'a, E: Engine> Circuit for MiMCDemo<'a, E> { fn synthesize>(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(); e }); 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(()) } }