forked from zkcrypto/bellman
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
128 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(()) | ||
} | ||
} |