diff --git a/snark/src/lib.rs b/snark/src/lib.rs index c6a3d76..33c267d 100644 --- a/snark/src/lib.rs +++ b/snark/src/lib.rs @@ -18,8 +18,23 @@ pub use self::g2::G2; extern "C" { fn libsnarkwrap_init(); fn libsnarkwrap_pairing(p: *const G1, q: *const G2) -> Gt; - fn libsnarkwrap_getcs(d: *mut libc::uint32_t, omega: *mut Fr) -> *mut libc::c_void; + fn libsnarkwrap_getcs(d: *mut libc::uint32_t, vars: *mut libc::uint32_t, omega: *mut Fr) -> *mut libc::c_void; fn libsnarkwrap_dropcs(cs: *mut libc::c_void); + fn libsnarkwrap_eval( + cs: *const libc::c_void, + lc: *const G1, + d: libc::uint32_t, + vars: libc::uint32_t, + At: *mut G1, + Bt: *mut G1, + Ct: *mut G1); + fn libsnarkwrap_test_eval( + cs: *const libc::c_void, + tau: *const Fr, + vars: libc::uint32_t, + At: *const G1, + Bt: *const G1, + Ct: *const G1) -> bool; fn libsnarkwrap_test_compare_tau( i: *const G1, tau: *const Fr, @@ -43,6 +58,41 @@ pub fn initialize() { pub struct CS(*mut libc::c_void); +impl CS { + pub fn test_eval(&self, tau: &Fr, At: &[G1], Bt: &[G1], Ct: &[G1]) -> bool { + assert_eq!(At.len(), Bt.len()); + assert_eq!(Bt.len(), Ct.len()); + + unsafe { + libsnarkwrap_test_eval(self.0, + tau, + At.len() as u32, + &At[0], + &Bt[0], + &Ct[0]) + } + } + + pub fn eval(&self, + Lt: &[G1], + At: &mut [G1], + Bt: &mut [G1], + Ct: &mut [G1]) { + assert_eq!(At.len(), Bt.len()); + assert_eq!(Bt.len(), Ct.len()); + + unsafe { + libsnarkwrap_eval(self.0, + &Lt[0], + Lt.len() as u32, + At.len() as u32, + &mut At[0], + &mut Bt[0], + &mut Ct[0]); + } + } +} + impl Drop for CS { fn drop(&mut self) { unsafe { libsnarkwrap_dropcs(self.0) } @@ -50,13 +100,14 @@ impl Drop for CS { } /// Get the QAP info for the generation routines -pub fn getqap() -> (usize, Fr, CS) { +pub fn getqap() -> (usize, usize, Fr, CS) { let mut d = 0; + let mut vars = 0; let mut o = Fr::zero(); - let cs = unsafe { libsnarkwrap_getcs(&mut d, &mut o) }; + let cs = unsafe { libsnarkwrap_getcs(&mut d, &mut vars, &mut o) }; - (d as usize, o, CS(cs)) + (d as usize, vars as usize, o, CS(cs)) } /// Check that the lagrange coefficients computed by tau over diff --git a/snark/src/libsnarkwrap.cpp b/snark/src/libsnarkwrap.cpp index f5e059b..095256c 100644 --- a/snark/src/libsnarkwrap.cpp +++ b/snark/src/libsnarkwrap.cpp @@ -172,7 +172,7 @@ extern "C" curve_GT libsnarkwrap_pairing(const curve_G1 *p, const curve_G2 *q) { // QAP -extern "C" void* libsnarkwrap_getcs(uint32_t *d, curve_Fr *omega) +extern "C" void* libsnarkwrap_getcs(uint32_t *d, uint32_t *vars, curve_Fr *omega) { // Generate a dummy circuit auto example = generate_r1cs_example_with_field_input(250, 4); @@ -184,6 +184,11 @@ extern "C" void* libsnarkwrap_getcs(uint32_t *d, curve_Fr *omega) // QAP reduction auto qap = r1cs_to_qap_instance_map(example.constraint_system); + // Sanity checks + assert(qap.A_in_Lagrange_basis.size() == example.constraint_system.num_variables()+1); + assert(qap.B_in_Lagrange_basis.size() == example.constraint_system.num_variables()+1); + assert(qap.C_in_Lagrange_basis.size() == example.constraint_system.num_variables()+1); + // Degree of the QAP must be a power of 2 assert(qap.degree() == 256); @@ -191,6 +196,7 @@ extern "C" void* libsnarkwrap_getcs(uint32_t *d, curve_Fr *omega) *omega = std::static_pointer_cast>(qap.domain)->omega; *d = qap.degree(); + *vars = example.constraint_system.num_variables()+1; } return new r1cs_constraint_system(example.constraint_system); @@ -220,3 +226,67 @@ extern "C" bool libsnarkwrap_test_compare_tau( return res; } + +extern "C" void libsnarkwrap_eval( + const r1cs_constraint_system *cs, + const curve_G1 *lc, + uint32_t d, + uint32_t vars, + curve_G1 *At, + curve_G1 *Bt, + curve_G1 *Ct +) +{ + auto qap = r1cs_to_qap_instance_map(*cs); + assert(qap.degree() == d); + assert(qap.A_in_Lagrange_basis.size() == vars); + assert(qap.B_in_Lagrange_basis.size() == vars); + assert(qap.C_in_Lagrange_basis.size() == vars); + + for (size_t i = 0; i < vars; i++) { + for (auto const &it : qap.A_in_Lagrange_basis[i]) { + assert(it.first < d); + At[i] = At[i] + it.second * lc[it.first]; + } + + for (auto const &it : qap.B_in_Lagrange_basis[i]) { + assert(it.first < d); + Bt[i] = Bt[i] + it.second * lc[it.first]; + } + + for (auto const &it : qap.C_in_Lagrange_basis[i]) { + assert(it.first < d); + Ct[i] = Ct[i] + it.second * lc[it.first]; + } + } +} + +extern "C" bool libsnarkwrap_test_eval( + const r1cs_constraint_system *cs, + const curve_Fr *tau, + uint32_t vars, + const curve_G1 *At, + const curve_G1 *Bt, + const curve_G1 *Ct +) { + auto qap = r1cs_to_qap_instance_map_with_evaluation(*cs, *tau); + assert(qap.At.size() == vars); + assert(qap.Bt.size() == vars); + assert(qap.Ct.size() == vars); + + bool res = true; + + for (size_t i = 0; i < vars; i++) { + res &= (qap.At[i] * curve_G1::one()) == At[i]; + } + + for (size_t i = 0; i < vars; i++) { + res &= (qap.Bt[i] * curve_G1::one()) == Bt[i]; + } + + for (size_t i = 0; i < vars; i++) { + res &= (qap.Ct[i] * curve_G1::one()) == Ct[i]; + } + + return res; +} diff --git a/src/fft.rs b/src/fft.rs index 5789587..a95ae0d 100644 --- a/src/fft.rs +++ b/src/fft.rs @@ -46,7 +46,7 @@ mod test { initialize(); // Get the QAP degree and omega (for FFT evaluation) - let (d, omega, cs) = getqap(); + let (d, num_vars, omega, cs) = getqap(); // Sample a random tau let tau = Fr::random(); @@ -66,5 +66,18 @@ mod test { // Wrong tau assert!(!compare_tau(&lc, &Fr::random(), &cs)); + + // Evaluate At, Bt, Ct in G1 + let mut At = (0..num_vars).map(|_| G1::zero()).collect::>(); + let mut Bt = (0..num_vars).map(|_| G1::zero()).collect::>(); + let mut Ct = (0..num_vars).map(|_| G1::zero()).collect::>(); + + cs.eval(&lc, &mut At, &mut Bt, &mut Ct); + + // Compare evaluation with libsnark + assert!(cs.test_eval(&tau, &At, &Bt, &Ct)); + + // Wrong tau + assert!(!cs.test_eval(&Fr::random(), &At, &Bt, &Ct)); } } diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index b0e8a4e..0253f93 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -21,13 +21,14 @@ pub struct Samples { pub struct Player { secrets: Samples, pub d: usize, + pub num_vars: usize, omega: Fr, cs: CS } impl Player { pub fn new() -> Player { - let (d, omega, cs) = getqap(); + let (d, num_vars, omega, cs) = getqap(); Player { secrets: Samples { @@ -41,6 +42,7 @@ impl Player { gamma: Fr::random_nonzero() }, d: d, + num_vars: num_vars, omega: omega, cs: cs }