From 61c70ed64409d05562b7ee1915f83fbdca1b7aea Mon Sep 17 00:00:00 2001 From: Weikeng Chen Date: Mon, 20 Jul 2020 15:42:25 -0700 Subject: [PATCH] Prepare Zexe for recursion (#241) Co-authored-by: Pratyush Mishra --- crypto-primitives/src/nizk/constraints.rs | 14 +- .../src/nizk/gm17/constraints.rs | 164 +++++++++++++- .../src/nizk/groth16/constraints.rs | 138 +++++++++++- r1cs-std/src/bits/boolean.rs | 57 +++++ r1cs-std/src/bits/uint32.rs | 2 +- r1cs-std/src/fields/fp/mod.rs | 9 + r1cs-std/src/fields/fp12.rs | 21 ++ r1cs-std/src/fields/fp2.rs | 19 ++ r1cs-std/src/fields/fp3.rs | 21 ++ r1cs-std/src/fields/fp4.rs | 21 ++ r1cs-std/src/fields/fp6_2over3.rs | 22 ++ r1cs-std/src/fields/fp6_3over2.rs | 23 ++ r1cs-std/src/fields/mod.rs | 10 +- .../curves/short_weierstrass/bls12/mod.rs | 88 +++++++- .../curves/short_weierstrass/mnt4/mod.rs | 204 +++++++++++++++++ .../curves/short_weierstrass/mnt6/mod.rs | 207 ++++++++++++++++++ .../groups/curves/short_weierstrass/mod.rs | 27 +++ .../src/groups/curves/twisted_edwards/mod.rs | 27 ++- r1cs-std/src/lib.rs | 2 +- r1cs-std/src/pairing/mod.rs | 10 +- 20 files changed, 1071 insertions(+), 15 deletions(-) diff --git a/crypto-primitives/src/nizk/constraints.rs b/crypto-primitives/src/nizk/constraints.rs index 61c4cb6..7b41463 100644 --- a/crypto-primitives/src/nizk/constraints.rs +++ b/crypto-primitives/src/nizk/constraints.rs @@ -5,9 +5,9 @@ use r1cs_std::prelude::*; use crate::nizk::NIZK; pub trait NIZKVerifierGadget { + type PreparedVerificationKeyGadget; type VerificationKeyGadget: AllocGadget + ToBytesGadget; - type ProofGadget: AllocGadget; fn check_verify<'a, CS, I, T>( @@ -32,4 +32,16 @@ pub trait NIZKVerifierGadget { CS: ConstraintSystem, I: Iterator, T: 'a + ToBitsGadget + ?Sized; + + fn conditional_check_verify_prepared<'a, CS, I, T>( + cs: CS, + prepared_verification_key: &Self::PreparedVerificationKeyGadget, + input: I, + proof: &Self::ProofGadget, + condition: &Boolean, + ) -> Result<(), SynthesisError> + where + CS: ConstraintSystem, + I: Iterator, + T: 'a + ToBitsGadget + ?Sized; } diff --git a/crypto-primitives/src/nizk/gm17/constraints.rs b/crypto-primitives/src/nizk/gm17/constraints.rs index 7c0c2f5..0ff042d 100644 --- a/crypto-primitives/src/nizk/gm17/constraints.rs +++ b/crypto-primitives/src/nizk/gm17/constraints.rs @@ -7,7 +7,7 @@ use r1cs_core::{ConstraintSynthesizer, ConstraintSystem, SynthesisError}; use r1cs_std::prelude::*; use core::{borrow::Borrow, marker::PhantomData}; -use gm17::{Proof, VerifyingKey}; +use gm17::{PreparedVerifyingKey, Proof, VerifyingKey}; #[derive(Derivative)] #[derivative(Clone(bound = "P::G1Gadget: Clone, P::G2Gadget: Clone"))] @@ -105,6 +105,7 @@ where V: ToConstraintField, P: PairingGadget, { + type PreparedVerificationKeyGadget = PreparedVerifyingKeyGadget; type VerificationKeyGadget = VerifyingKeyGadget; type ProofGadget = ProofGadget; @@ -131,7 +132,7 @@ where fn conditional_check_verify<'a, CS, I, T>( mut cs: CS, vk: &Self::VerificationKeyGadget, - mut public_inputs: I, + public_inputs: I, proof: &Self::ProofGadget, condition: &Boolean, ) -> Result<(), SynthesisError> @@ -141,9 +142,24 @@ where T: 'a + ToBitsGadget + ?Sized, { let pvk = vk.prepare(&mut cs.ns(|| "Prepare vk"))?; + , ConstraintF>>::conditional_check_verify_prepared(cs, &pvk, public_inputs, proof, condition) + } + + fn conditional_check_verify_prepared<'a, CS, I, T>( + mut cs: CS, + pvk: &Self::PreparedVerificationKeyGadget, + mut public_inputs: I, + proof: &Self::ProofGadget, + condition: &Boolean, + ) -> Result<(), SynthesisError> + where + CS: ConstraintSystem, + I: Iterator, + T: 'a + ToBitsGadget + ?Sized, + { + let pvk = pvk.clone(); // e(A*G^{alpha}, B*H^{beta}) = e(G^{alpha}, H^{beta}) * e(G^{psi}, H^{gamma}) * // e(C, H) where psi = \sum_{i=0}^l input_i pvk.query[i] - let g_psi = { let mut cs = cs.ns(|| "Process input"); let mut g_psi = pvk.query[0].clone(); @@ -216,6 +232,148 @@ where } } +impl AllocGadget, ConstraintF> + for PreparedVerifyingKeyGadget +where + PairingE: PairingEngine, + ConstraintF: Field, + P: PairingGadget, + P::G1PreparedGadget: AllocGadget, + P::G2PreparedGadget: AllocGadget, +{ + #[inline] + fn alloc_constant>( + mut cs: CS, + val: T, + ) -> Result + where + T: Borrow>, + { + let pvk = val.borrow().clone(); + + let g_alpha = + P::G1Gadget::alloc_constant(cs.ns(|| "g_alpha"), pvk.g_alpha.into_projective())?; + let h_beta = P::G2Gadget::alloc_constant(cs.ns(|| "h_beta"), pvk.h_beta.into_projective())?; + let g_alpha_pc = + P::G1PreparedGadget::alloc_constant(cs.ns(|| "g_alpha_pc"), pvk.g_alpha.into())?; + let h_beta_pc = + P::G2PreparedGadget::alloc_constant(cs.ns(|| "h_beta_pc"), pvk.h_beta.into())?; + let g_gamma_pc = + P::G1PreparedGadget::alloc_constant(cs.ns(|| "g_gamma_pc"), pvk.g_gamma_pc)?; + let h_gamma_pc = + P::G2PreparedGadget::alloc_constant(cs.ns(|| "h_gamma_pc"), pvk.h_gamma_pc)?; + let h_pc = P::G2PreparedGadget::alloc_constant(cs.ns(|| "h_pc"), pvk.h_pc)?; + + let mut query = Vec::::new(); + for (i, item) in pvk.query.iter().enumerate() { + query.push(P::G1Gadget::alloc_constant( + &mut cs.ns(|| format!("query_{}", i)), + item.borrow().into_projective(), + )?); + } + + Ok(Self { + g_alpha, + h_beta, + g_alpha_pc, + h_beta_pc, + g_gamma_pc, + h_gamma_pc, + h_pc, + query, + }) + } + + #[inline] + fn alloc>( + mut cs: CS, + value_gen: FN, + ) -> Result + where + FN: FnOnce() -> Result, + T: Borrow>, + { + let pvk = value_gen()?.borrow().clone(); + + let g_alpha = + P::G1Gadget::alloc(cs.ns(|| "g_alpha"), || Ok(pvk.g_alpha.into_projective()))?; + let h_beta = P::G2Gadget::alloc(cs.ns(|| "h_beta"), || Ok(pvk.h_beta.into_projective()))?; + let g_alpha_pc = + P::G1PreparedGadget::alloc(cs.ns(|| "g_alpha_pc"), || Ok(pvk.g_alpha.into()))?; + let h_beta_pc = + P::G2PreparedGadget::alloc(cs.ns(|| "h_beta_pc"), || Ok(pvk.h_beta.into()))?; + let g_gamma_pc = + P::G1PreparedGadget::alloc(cs.ns(|| "g_gamma_pc"), || Ok(&pvk.g_gamma_pc))?; + let h_gamma_pc = + P::G2PreparedGadget::alloc(cs.ns(|| "h_gamma_pc"), || Ok(&pvk.h_gamma_pc))?; + let h_pc = P::G2PreparedGadget::alloc(cs.ns(|| "h_pc"), || Ok(&pvk.h_pc))?; + + let mut query = Vec::::new(); + for (i, item) in pvk.query.iter().enumerate() { + query.push(P::G1Gadget::alloc( + cs.ns(|| format!("query_{}", i)), + || Ok(item.borrow().into_projective()), + )?); + } + + Ok(Self { + g_alpha, + h_beta, + g_alpha_pc, + h_beta_pc, + g_gamma_pc, + h_gamma_pc, + h_pc, + query, + }) + } + + #[inline] + fn alloc_input>( + mut cs: CS, + value_gen: FN, + ) -> Result + where + FN: FnOnce() -> Result, + T: Borrow>, + { + let pvk = value_gen()?.borrow().clone(); + + let g_alpha = + P::G1Gadget::alloc_input(cs.ns(|| "g_alpha"), || Ok(pvk.g_alpha.into_projective()))?; + let h_beta = + P::G2Gadget::alloc_input(cs.ns(|| "h_beta"), || Ok(pvk.h_beta.into_projective()))?; + let g_alpha_pc = + P::G1PreparedGadget::alloc_input(cs.ns(|| "g_alpha_pc"), || Ok(pvk.g_alpha.into()))?; + let h_beta_pc = + P::G2PreparedGadget::alloc_input(cs.ns(|| "h_beta_pc"), || Ok(pvk.h_beta.into()))?; + let g_gamma_pc = + P::G1PreparedGadget::alloc_input(cs.ns(|| "g_gamma_pc"), || Ok(&pvk.g_gamma_pc))?; + let h_gamma_pc = + P::G2PreparedGadget::alloc_input(cs.ns(|| "h_gamma_pc"), || Ok(&pvk.h_gamma_pc))?; + let h_pc = P::G2PreparedGadget::alloc_input(cs.ns(|| "h_pc"), || Ok(&pvk.h_pc))?; + + let mut query = Vec::::new(); + for (i, item) in pvk.query.iter().enumerate() { + query.push(P::G1Gadget::alloc_input( + &mut cs.ns(|| format!("query_{}", i)), + || Ok(item.borrow().into_projective()), + )?); + } + + Ok(Self { + g_alpha, + h_beta, + g_alpha_pc, + h_beta_pc, + g_gamma_pc, + h_gamma_pc, + h_pc, + query, + }) + } +} + impl AllocGadget, ConstraintF> for VerifyingKeyGadget where diff --git a/crypto-primitives/src/nizk/groth16/constraints.rs b/crypto-primitives/src/nizk/groth16/constraints.rs index dbf2dc8..bef31bd 100644 --- a/crypto-primitives/src/nizk/groth16/constraints.rs +++ b/crypto-primitives/src/nizk/groth16/constraints.rs @@ -7,7 +7,7 @@ use r1cs_core::{ConstraintSynthesizer, ConstraintSystem, SynthesisError}; use r1cs_std::prelude::*; use core::{borrow::Borrow, marker::PhantomData}; -use groth16::{Proof, VerifyingKey}; +use groth16::{PreparedVerifyingKey, Proof, VerifyingKey}; #[derive(Derivative)] #[derivative(Clone(bound = "P::G1Gadget: Clone, P::G2Gadget: Clone"))] @@ -106,6 +106,7 @@ where V: ToConstraintField, P: PairingGadget, { + type PreparedVerificationKeyGadget = PreparedVerifyingKeyGadget; type VerificationKeyGadget = VerifyingKeyGadget; type ProofGadget = ProofGadget; @@ -132,7 +133,7 @@ where fn conditional_check_verify<'a, CS, I, T>( mut cs: CS, vk: &Self::VerificationKeyGadget, - mut public_inputs: I, + public_inputs: I, proof: &Self::ProofGadget, condition: &Boolean, ) -> Result<(), SynthesisError> @@ -142,6 +143,22 @@ where T: 'a + ToBitsGadget + ?Sized, { let pvk = vk.prepare(&mut cs.ns(|| "Prepare vk"))?; + , ConstraintF>>::conditional_check_verify_prepared(cs, &pvk, public_inputs, proof, condition) + } + + fn conditional_check_verify_prepared<'a, CS, I, T>( + mut cs: CS, + pvk: &Self::PreparedVerificationKeyGadget, + mut public_inputs: I, + proof: &Self::ProofGadget, + condition: &Boolean, + ) -> Result<(), SynthesisError> + where + CS: ConstraintSystem, + I: Iterator, + T: 'a + ToBitsGadget + ?Sized, + { + let pvk = pvk.clone(); let g_ic = { let mut cs = cs.ns(|| "Process input"); @@ -187,6 +204,123 @@ where } } +impl AllocGadget, ConstraintF> + for PreparedVerifyingKeyGadget +where + PairingE: PairingEngine, + ConstraintF: Field, + P: PairingGadget, + P::G2PreparedGadget: AllocGadget, +{ + fn alloc_constant>( + mut cs: CS, + val: T, + ) -> Result + where + T: Borrow>, + { + let pvk = val.borrow().clone(); + + let alpha_g1_beta_g2 = + P::GTGadget::alloc_constant(cs.ns(|| "alpha_g1_beta_g2"), pvk.alpha_g1_beta_g2)?; + + let gamma_g2_neg_pc = + P::G2PreparedGadget::alloc_constant(cs.ns(|| "gamma_g2_neg_pc"), pvk.gamma_g2_neg_pc)?; + + let delta_g2_neg_pc = + P::G2PreparedGadget::alloc_constant(cs.ns(|| "delta_g2_neg_pc"), pvk.delta_g2_neg_pc)?; + + let mut gamma_abc_g1 = Vec::::new(); + for (i, item) in pvk.gamma_abc_g1.iter().enumerate() { + gamma_abc_g1.push(P::G1Gadget::alloc_constant( + cs.ns(|| format!("query_{}", i)), + item.borrow().into_projective(), + )?); + } + + Ok(Self { + alpha_g1_beta_g2, + gamma_g2_neg_pc, + delta_g2_neg_pc, + gamma_abc_g1, + }) + } + + fn alloc>( + mut cs: CS, + f: F, + ) -> Result + where + F: FnOnce() -> Result, + T: Borrow>, + { + let pvk = f()?.borrow().clone(); + + let alpha_g1_beta_g2 = + P::GTGadget::alloc(cs.ns(|| "alpha_g1_beta_g2"), || Ok(pvk.alpha_g1_beta_g2))?; + + let gamma_g2_neg_pc = + P::G2PreparedGadget::alloc(cs.ns(|| "gamma_g2_neg_pc"), || Ok(&pvk.gamma_g2_neg_pc))?; + + let delta_g2_neg_pc = + P::G2PreparedGadget::alloc(cs.ns(|| "delta_g2_neg_pc"), || Ok(&pvk.delta_g2_neg_pc))?; + + let mut gamma_abc_g1 = Vec::::new(); + for (i, item) in pvk.gamma_abc_g1.iter().enumerate() { + gamma_abc_g1.push(P::G1Gadget::alloc( + cs.ns(|| format!("query_{}", i)), + || Ok(item.borrow().into_projective()), + )?); + } + + Ok(Self { + alpha_g1_beta_g2, + gamma_g2_neg_pc, + delta_g2_neg_pc, + gamma_abc_g1, + }) + } + + fn alloc_input>( + mut cs: CS, + f: F, + ) -> Result + where + F: FnOnce() -> Result, + T: Borrow>, + { + let pvk = f()?.borrow().clone(); + + let alpha_g1_beta_g2 = + P::GTGadget::alloc_input(cs.ns(|| "alpha_g1_beta_g2"), || Ok(pvk.alpha_g1_beta_g2))?; + + let gamma_g2_neg_pc = + P::G2PreparedGadget::alloc_input(cs.ns(|| "gamma_g2_neg_pc"), || { + Ok(&pvk.gamma_g2_neg_pc) + })?; + + let delta_g2_neg_pc = + P::G2PreparedGadget::alloc_input(cs.ns(|| "delta_g2_neg_pc"), || { + Ok(&pvk.delta_g2_neg_pc) + })?; + + let mut gamma_abc_g1 = Vec::::new(); + for (i, item) in pvk.gamma_abc_g1.iter().enumerate() { + gamma_abc_g1.push(P::G1Gadget::alloc_input( + cs.ns(|| format!("query_{}", i)), + || Ok(item.borrow().into_projective()), + )?); + } + + Ok(Self { + alpha_g1_beta_g2, + gamma_g2_neg_pc, + delta_g2_neg_pc, + gamma_abc_g1, + }) + } +} + impl AllocGadget, ConstraintF> for VerifyingKeyGadget where diff --git a/r1cs-std/src/bits/boolean.rs b/r1cs-std/src/bits/boolean.rs index ed48a22..21dc922 100644 --- a/r1cs-std/src/bits/boolean.rs +++ b/r1cs-std/src/bits/boolean.rs @@ -852,6 +852,63 @@ impl ToBytesGadget for Boolean { } } +impl ToConstraintFieldGadget for Boolean { + fn to_constraint_field>( + &self, + mut cs: CS, + ) -> Result>, SynthesisError> { + let gadget = match self { + Boolean::Constant(cond) => { + if *cond { + FpGadget::one(&mut cs.ns(|| "one"))? + } else { + FpGadget::zero(&mut cs.ns(|| "zero"))? + } + } + Boolean::Is(allocated_bit) => { + let value = match self.get_value() { + None => None, + Some(bool) => { + if bool { + Some(ConstraintF::one()) + } else { + Some(ConstraintF::zero()) + } + } + }; + + FpGadget:: { + value, + variable: ConstraintVar::Var(allocated_bit.get_variable()), + } + } + Boolean::Not(allocated_bit) => { + let value = match self.get_value() { + None => None, + Some(bool) => { + if bool { + Some(ConstraintF::zero()) + } else { + Some(ConstraintF::one()) + } + } + }; + + let mut lc = LinearCombination::::zero(); + lc += (ConstraintF::one(), CS::one()); + lc += (-ConstraintF::one(), allocated_bit.get_variable()); + + FpGadget:: { + value, + variable: ConstraintVar::LC(lc), + } + } + }; + + Ok(vec![gadget]) + } +} + impl CondSelectGadget for Boolean { fn conditionally_select( mut cs: CS, diff --git a/r1cs-std/src/bits/uint32.rs b/r1cs-std/src/bits/uint32.rs index 6029015..be65918 100644 --- a/r1cs-std/src/bits/uint32.rs +++ b/r1cs-std/src/bits/uint32.rs @@ -14,7 +14,7 @@ use crate::{ pub struct UInt32 { // Least significant bit_gadget first bits: Vec, - value: Option, + pub value: Option, } impl UInt32 { diff --git a/r1cs-std/src/fields/fp/mod.rs b/r1cs-std/src/fields/fp/mod.rs index 47d592b..da8192c 100644 --- a/r1cs-std/src/fields/fp/mod.rs +++ b/r1cs-std/src/fields/fp/mod.rs @@ -40,6 +40,15 @@ impl FpGadget { } } +impl ToConstraintFieldGadget for FpGadget { + fn to_constraint_field>( + &self, + _cs: CS, + ) -> Result>, SynthesisError> { + Ok(vec![self.clone()]) + } +} + impl FieldGadget for FpGadget { type Variable = ConstraintVar; diff --git a/r1cs-std/src/fields/fp12.rs b/r1cs-std/src/fields/fp12.rs index 4ead2b5..b2248b0 100644 --- a/r1cs-std/src/fields/fp12.rs +++ b/r1cs-std/src/fields/fp12.rs @@ -37,6 +37,27 @@ where _params: PhantomData

, } +impl ToConstraintFieldGadget for Fp12Gadget +where + P: Fp12Parameters, + ::Fp2Params: Fp2Parameters, +{ + fn to_constraint_field>( + &self, + mut cs: CS, + ) -> Result>, SynthesisError> { + let mut res = Vec::new(); + + let mut c0_gadget = self.c0.to_constraint_field(&mut cs.ns(|| "c0"))?; + let mut c1_gadget = self.c1.to_constraint_field(&mut cs.ns(|| "c1"))?; + + res.append(&mut c0_gadget); + res.append(&mut c1_gadget); + + Ok(res) + } +} + impl Fp12Gadget where P: Fp12Parameters, diff --git a/r1cs-std/src/fields/fp2.rs b/r1cs-std/src/fields/fp2.rs index 476ecc5..ee3b3ff 100644 --- a/r1cs-std/src/fields/fp2.rs +++ b/r1cs-std/src/fields/fp2.rs @@ -17,6 +17,25 @@ pub struct Fp2Gadget, ConstraintF: PrimeField _params: PhantomData

, } +impl, ConstraintF: PrimeField> + ToConstraintFieldGadget for Fp2Gadget +{ + fn to_constraint_field>( + &self, + mut cs: CS, + ) -> Result>, SynthesisError> { + let mut res = Vec::new(); + + let mut c0_gadget = self.c0.to_constraint_field(&mut cs.ns(|| "c0"))?; + let mut c1_gadget = self.c1.to_constraint_field(&mut cs.ns(|| "c1"))?; + + res.append(&mut c0_gadget); + res.append(&mut c1_gadget); + + Ok(res) + } +} + impl, ConstraintF: PrimeField> Fp2Gadget { pub fn new(c0: FpGadget, c1: FpGadget) -> Self { Self { diff --git a/r1cs-std/src/fields/fp3.rs b/r1cs-std/src/fields/fp3.rs index 6ab72c7..2c852c7 100644 --- a/r1cs-std/src/fields/fp3.rs +++ b/r1cs-std/src/fields/fp3.rs @@ -21,6 +21,27 @@ pub struct Fp3Gadget, ConstraintF: PrimeField _params: PhantomData

, } +impl, ConstraintF: PrimeField + SquareRootField> + ToConstraintFieldGadget for Fp3Gadget +{ + fn to_constraint_field>( + &self, + mut cs: CS, + ) -> Result>, SynthesisError> { + let mut res = Vec::new(); + + let mut c0_gadget = self.c0.to_constraint_field(&mut cs.ns(|| "c0"))?; + let mut c1_gadget = self.c1.to_constraint_field(&mut cs.ns(|| "c1"))?; + let mut c2_gadget = self.c2.to_constraint_field(&mut cs.ns(|| "c2"))?; + + res.append(&mut c0_gadget); + res.append(&mut c1_gadget); + res.append(&mut c2_gadget); + + Ok(res) + } +} + impl, ConstraintF: PrimeField + SquareRootField> Fp3Gadget { diff --git a/r1cs-std/src/fields/fp4.rs b/r1cs-std/src/fields/fp4.rs index 91c0da6..d04264e 100644 --- a/r1cs-std/src/fields/fp4.rs +++ b/r1cs-std/src/fields/fp4.rs @@ -28,6 +28,27 @@ where _params: PhantomData

, } +impl ToConstraintFieldGadget for Fp4Gadget +where + P: Fp4Parameters, + P::Fp2Params: Fp2Parameters, +{ + fn to_constraint_field>( + &self, + mut cs: CS, + ) -> Result>, SynthesisError> { + let mut res = Vec::new(); + + let mut c0_gadget = self.c0.to_constraint_field(&mut cs.ns(|| "c0"))?; + let mut c1_gadget = self.c1.to_constraint_field(&mut cs.ns(|| "c1"))?; + + res.append(&mut c0_gadget); + res.append(&mut c1_gadget); + + Ok(res) + } +} + impl Fp4Gadget where P: Fp4Parameters, diff --git a/r1cs-std/src/fields/fp6_2over3.rs b/r1cs-std/src/fields/fp6_2over3.rs index 5c4a79a..f889627 100644 --- a/r1cs-std/src/fields/fp6_2over3.rs +++ b/r1cs-std/src/fields/fp6_2over3.rs @@ -31,6 +31,28 @@ where _params: PhantomData

, } +impl ToConstraintFieldGadget + for Fp6Gadget +where + P: Fp6Parameters, + P::Fp3Params: Fp3Parameters, +{ + fn to_constraint_field>( + &self, + mut cs: CS, + ) -> Result>, SynthesisError> { + let mut res = Vec::new(); + + let mut c0_gadget = self.c0.to_constraint_field(&mut cs.ns(|| "c0"))?; + let mut c1_gadget = self.c1.to_constraint_field(&mut cs.ns(|| "c1"))?; + + res.append(&mut c0_gadget); + res.append(&mut c1_gadget); + + Ok(res) + } +} + impl Fp6Gadget where P: Fp6Parameters, diff --git a/r1cs-std/src/fields/fp6_3over2.rs b/r1cs-std/src/fields/fp6_3over2.rs index f4b25e7..22e3a48 100644 --- a/r1cs-std/src/fields/fp6_3over2.rs +++ b/r1cs-std/src/fields/fp6_3over2.rs @@ -28,6 +28,29 @@ where _params: PhantomData

, } +impl ToConstraintFieldGadget for Fp6Gadget +where + P: Fp6Parameters, + P::Fp2Params: Fp2Parameters, +{ + fn to_constraint_field>( + &self, + mut cs: CS, + ) -> Result>, SynthesisError> { + let mut res = Vec::new(); + + let mut c0_gadget = self.c0.to_constraint_field(&mut cs.ns(|| "c0"))?; + let mut c1_gadget = self.c1.to_constraint_field(&mut cs.ns(|| "c1"))?; + let mut c2_gadget = self.c2.to_constraint_field(&mut cs.ns(|| "c2"))?; + + res.append(&mut c0_gadget); + res.append(&mut c1_gadget); + res.append(&mut c2_gadget); + + Ok(res) + } +} + impl Fp6Gadget where P: Fp6Parameters, diff --git a/r1cs-std/src/fields/mod.rs b/r1cs-std/src/fields/mod.rs index 3df2d0e..a4ea67e 100644 --- a/r1cs-std/src/fields/mod.rs +++ b/r1cs-std/src/fields/mod.rs @@ -1,4 +1,4 @@ -use algebra::{fields::BitIterator, Field}; +use algebra::{fields::BitIterator, Field, PrimeField, Vec}; use core::fmt::Debug; use r1cs_core::{ConstraintSystem, SynthesisError}; @@ -12,6 +12,14 @@ pub mod fp4; pub mod fp6_2over3; pub mod fp6_3over2; +use crate::fields::fp::FpGadget; +pub trait ToConstraintFieldGadget { + fn to_constraint_field>( + &self, + cs: CS, + ) -> Result>, SynthesisError>; +} + pub trait FieldGadget: Sized + Clone diff --git a/r1cs-std/src/groups/curves/short_weierstrass/bls12/mod.rs b/r1cs-std/src/groups/curves/short_weierstrass/bls12/mod.rs index 534793b..7494b3b 100644 --- a/r1cs-std/src/groups/curves/short_weierstrass/bls12/mod.rs +++ b/r1cs-std/src/groups/curves/short_weierstrass/bls12/mod.rs @@ -1,5 +1,5 @@ use algebra::{ - curves::bls12::{Bls12Parameters, G1Prepared, TwistType}, + curves::bls12::{Bls12Parameters, G1Prepared, G2Prepared, TwistType}, fields::Field, BitIterator, One, ProjectiveCurve, }; @@ -12,7 +12,7 @@ use crate::{ Vec, }; -use core::fmt::Debug; +use core::{borrow::Borrow, fmt::Debug, ops::Mul}; pub type G1Gadget

= AffineGadget<

::G1Parameters, @@ -30,6 +30,42 @@ pub type G2Gadget

= )] pub struct G1PreparedGadget(pub G1Gadget

); +impl AllocGadget, P::Fp> for G1PreparedGadget

{ + fn alloc_constant>( + mut cs: CS, + t: T, + ) -> Result + where + T: Borrow>, + { + let obj = t.borrow(); + + Ok(Self(G1Gadget::

::alloc_constant( + &mut cs.ns(|| "g1"), + &obj.0.into(), + )?)) + } + + fn alloc>(_cs: CS, _f: F) -> Result + where + F: FnOnce() -> Result, + T: Borrow>, + { + todo!() + } + + fn alloc_input>( + _cs: CS, + _f: F, + ) -> Result + where + F: FnOnce() -> Result, + T: Borrow>, + { + todo!() + } +} + impl G1PreparedGadget

{ pub fn get_value(&self) -> Option> { Some(G1Prepared::from(self.0.get_value().unwrap().into_affine())) @@ -72,6 +108,54 @@ pub struct G2PreparedGadget { pub ell_coeffs: Vec>, } +impl AllocGadget, P::Fp> for G2PreparedGadget

{ + fn alloc_constant>( + mut cs: CS, + t: T, + ) -> Result + where + T: Borrow>, + { + let obj = t.borrow(); + let mut res = Vec::>::new(); + + for (i, (x, y, z)) in obj.ell_coeffs.iter().enumerate() { + let z_inverse = z.inverse().unwrap(); + + let x_normalized = x.mul(&z_inverse); + let y_normalized = y.mul(&z_inverse); + + let x_gadget = + Fp2Gadget::alloc_constant(&mut cs.ns(|| format!("alloc_x#{}", i)), x_normalized)?; + let y_gadget = + Fp2Gadget::alloc_constant(&mut cs.ns(|| format!("alloc_y#{}", i)), y_normalized)?; + + res.push((x_gadget, y_gadget)); + } + + Ok(Self { ell_coeffs: res }) + } + + fn alloc>(_cs: CS, _f: F) -> Result + where + F: FnOnce() -> Result, + T: Borrow>, + { + todo!() + } + + fn alloc_input>( + _cs: CS, + _f: F, + ) -> Result + where + F: FnOnce() -> Result, + T: Borrow>, + { + todo!() + } +} + impl ToBytesGadget for G2PreparedGadget

{ #[inline] fn to_bytes>( diff --git a/r1cs-std/src/groups/curves/short_weierstrass/mnt4/mod.rs b/r1cs-std/src/groups/curves/short_weierstrass/mnt4/mod.rs index 2ecfdbf..def96b4 100644 --- a/r1cs-std/src/groups/curves/short_weierstrass/mnt4/mod.rs +++ b/r1cs-std/src/groups/curves/short_weierstrass/mnt4/mod.rs @@ -14,6 +14,7 @@ use crate::{ prelude::*, Vec, }; +use core::borrow::Borrow; pub type G1Gadget

= AffineGadget<

::G1Parameters, @@ -72,6 +73,53 @@ impl G1PreparedGadget

{ } } +impl AllocGadget, P::Fp> for G1PreparedGadget

{ + fn alloc_constant>( + mut cs: CS, + t: T, + ) -> Result + where + T: Borrow>, + { + let obj = t.borrow(); + let x = FpGadget::::alloc_constant(&mut cs.ns(|| "alloc_x"), &obj.x)?; + let y = FpGadget::::alloc_constant(&mut cs.ns(|| "alloc_y"), &obj.y)?; + let x_twist = Fp2Gadget::::alloc_constant( + &mut cs.ns(|| "alloc_x_twist"), + &obj.x_twist, + )?; + let y_twist = Fp2Gadget::::alloc_constant( + &mut cs.ns(|| "alloc_y_twist"), + &obj.y_twist, + )?; + Ok(G1PreparedGadget { + x, + y, + x_twist, + y_twist, + }) + } + + fn alloc>(_cs: CS, _f: F) -> Result + where + F: FnOnce() -> Result, + T: Borrow>, + { + todo!() + } + + fn alloc_input>( + _cs: CS, + _f: F, + ) -> Result + where + F: FnOnce() -> Result, + T: Borrow>, + { + todo!() + } +} + impl ToBytesGadget for G1PreparedGadget

{ #[inline] fn to_bytes>( @@ -121,6 +169,70 @@ pub struct G2PreparedGadget { pub addition_coefficients: Vec>, } +impl AllocGadget, P::Fp> for G2PreparedGadget

{ + fn alloc_constant>( + mut cs: CS, + t: T, + ) -> Result + where + T: Borrow>, + { + let obj = t.borrow(); + let x = Fp2Gadget::::alloc_constant(&mut cs.ns(|| "alloc_x"), &obj.x)?; + let y = Fp2Gadget::::alloc_constant(&mut cs.ns(|| "alloc_y"), &obj.y)?; + let x_over_twist = Fp2Gadget::::alloc_constant( + &mut cs.ns(|| "alloc_x_over_twist"), + &obj.x_over_twist, + )?; + let y_over_twist = Fp2Gadget::::alloc_constant( + &mut cs.ns(|| "alloc_y_over_twist"), + &obj.y_over_twist, + )?; + let mut double_coefficients = Vec::>::new(); + for (i, item) in obj.double_coefficients.iter().enumerate() { + double_coefficients.push(AteDoubleCoefficientsGadget::

::alloc_constant( + &mut cs.ns(|| format!("alloc_double_coefficients_{}", i)), + item, + )?); + } + let mut addition_coefficients = Vec::>::new(); + for (i, item) in obj.addition_coefficients.iter().enumerate() { + addition_coefficients.push(AteAdditionCoefficientsGadget::

::alloc_constant( + &mut cs.ns(|| format!("alloc_addition_coefficients_{}", i)), + item, + )?); + } + + Ok(G2PreparedGadget { + x, + y, + x_over_twist, + y_over_twist, + double_coefficients, + addition_coefficients, + }) + } + + fn alloc>(_cs: CS, _f: F) -> Result + where + F: FnOnce() -> Result, + T: Borrow>, + { + todo!() + } + + fn alloc_input>( + _cs: CS, + _f: F, + ) -> Result + where + F: FnOnce() -> Result, + T: Borrow>, + { + todo!() + } +} + impl ToBytesGadget for G2PreparedGadget

{ #[inline] fn to_bytes>( @@ -308,6 +420,56 @@ pub struct AteDoubleCoefficientsGadget { pub c_l: Fp2Gadget, } +impl AllocGadget, P::Fp> + for AteDoubleCoefficientsGadget

+{ + fn alloc_constant>( + mut cs: CS, + t: T, + ) -> Result + where + T: Borrow>, + { + let obj = t.borrow(); + let c_h = + Fp2Gadget::::alloc_constant(&mut cs.ns(|| "alloc_c_h"), &obj.c_h)?; + let c_4c = Fp2Gadget::::alloc_constant( + &mut cs.ns(|| "alloc_c_4c"), + &obj.c_4c, + )?; + let c_j = + Fp2Gadget::::alloc_constant(&mut cs.ns(|| "alloc_c_j"), &obj.c_j)?; + let c_l = + Fp2Gadget::::alloc_constant(&mut cs.ns(|| "alloc_c_l"), &obj.c_l)?; + + Ok(AteDoubleCoefficientsGadget { + c_h, + c_4c, + c_j, + c_l, + }) + } + + fn alloc>(_cs: CS, _f: F) -> Result + where + F: FnOnce() -> Result, + T: Borrow>, + { + todo!() + } + + fn alloc_input>( + _cs: CS, + _f: F, + ) -> Result + where + F: FnOnce() -> Result, + T: Borrow>, + { + todo!() + } +} + impl ToBytesGadget for AteDoubleCoefficientsGadget

{ #[inline] fn to_bytes>( @@ -375,6 +537,48 @@ pub struct AteAdditionCoefficientsGadget { pub c_rz: Fp2Gadget, } +impl AllocGadget, P::Fp> + for AteAdditionCoefficientsGadget

+{ + fn alloc_constant>( + mut cs: CS, + t: T, + ) -> Result + where + T: Borrow>, + { + let obj = t.borrow(); + let c_l1 = Fp2Gadget::::alloc_constant( + &mut cs.ns(|| "alloc_c_l1"), + &obj.c_l1, + )?; + let c_rz = Fp2Gadget::::alloc_constant( + &mut cs.ns(|| "alloc_c_rz"), + &obj.c_rz, + )?; + Ok(AteAdditionCoefficientsGadget { c_l1, c_rz }) + } + + fn alloc>(_cs: CS, _f: F) -> Result + where + F: FnOnce() -> Result, + T: Borrow>, + { + todo!() + } + + fn alloc_input>( + _cs: CS, + _f: F, + ) -> Result + where + F: FnOnce() -> Result, + T: Borrow>, + { + todo!() + } +} + impl ToBytesGadget for AteAdditionCoefficientsGadget

{ #[inline] fn to_bytes>( diff --git a/r1cs-std/src/groups/curves/short_weierstrass/mnt6/mod.rs b/r1cs-std/src/groups/curves/short_weierstrass/mnt6/mod.rs index 8929757..7318c13 100644 --- a/r1cs-std/src/groups/curves/short_weierstrass/mnt6/mod.rs +++ b/r1cs-std/src/groups/curves/short_weierstrass/mnt6/mod.rs @@ -5,6 +5,7 @@ use algebra::{ }, Field, }; +use core::borrow::Borrow; use r1cs_core::{ConstraintSystem, SynthesisError}; use crate::{ @@ -33,6 +34,55 @@ pub struct G1PreparedGadget { pub y_twist: Fp3Gadget, } +impl AllocGadget, P::Fp> for G1PreparedGadget

{ + fn alloc_constant>( + mut cs: CS, + t: T, + ) -> Result + where + T: Borrow>, + { + let obj = t.borrow(); + + let x_gadget = FpGadget::::alloc_constant(&mut cs.ns(|| "x"), &obj.x)?; + let y_gadget = FpGadget::::alloc_constant(&mut cs.ns(|| "y"), &obj.y)?; + let x_twist_gadget = Fp3Gadget::::alloc_constant( + &mut cs.ns(|| "x_twist"), + &obj.x_twist, + )?; + let y_twist_gadget = Fp3Gadget::::alloc_constant( + &mut cs.ns(|| "y_twist"), + &obj.y_twist, + )?; + + Ok(Self { + x: x_gadget, + y: y_gadget, + x_twist: x_twist_gadget, + y_twist: y_twist_gadget, + }) + } + + fn alloc>(_cs: CS, _f: F) -> Result + where + F: FnOnce() -> Result, + T: Borrow>, + { + todo!() + } + + fn alloc_input>( + _cs: CS, + _f: F, + ) -> Result + where + F: FnOnce() -> Result, + T: Borrow>, + { + todo!() + } +} + impl G1PreparedGadget

{ pub fn get_value(&self) -> Option> { match ( @@ -123,6 +173,76 @@ pub struct G2PreparedGadget { pub addition_coefficients: Vec>, } +impl AllocGadget, P::Fp> for G2PreparedGadget

{ + fn alloc_constant>( + mut cs: CS, + t: T, + ) -> Result + where + T: Borrow>, + { + let obj = t.borrow(); + + let x_gadget = + Fp3Gadget::::alloc_constant(&mut cs.ns(|| "x"), &obj.x)?; + let y_gadget = + Fp3Gadget::::alloc_constant(&mut cs.ns(|| "y"), &obj.y)?; + + let x_over_twist_gadget = Fp3Gadget::::alloc_constant( + &mut cs.ns(|| "x_over_twist"), + &obj.x_over_twist, + )?; + let y_over_twist_gadget = Fp3Gadget::::alloc_constant( + &mut cs.ns(|| "y_over_twist"), + &obj.y_over_twist, + )?; + + let mut double_coefficients_gadget = Vec::>::new(); + for (i, double_coefficient) in obj.double_coefficients.iter().enumerate() { + double_coefficients_gadget.push(AteDoubleCoefficientsGadget::

::alloc_constant( + &mut cs.ns(|| format!("double_coefficient#{}", i)), + double_coefficient, + )?); + } + + let mut addition_coefficients_gadget = Vec::>::new(); + for (i, addition_coefficient) in obj.addition_coefficients.iter().enumerate() { + addition_coefficients_gadget.push(AteAdditionCoefficientsGadget::

::alloc_constant( + &mut cs.ns(|| format!("addition_coefficient#{}", i)), + addition_coefficient, + )?); + } + + Ok(Self { + x: x_gadget, + y: y_gadget, + x_over_twist: x_over_twist_gadget, + y_over_twist: y_over_twist_gadget, + double_coefficients: double_coefficients_gadget, + addition_coefficients: addition_coefficients_gadget, + }) + } + + fn alloc>(_cs: CS, _f: F) -> Result + where + F: FnOnce() -> Result, + T: Borrow>, + { + todo!() + } + + fn alloc_input>( + _cs: CS, + _f: F, + ) -> Result + where + F: FnOnce() -> Result, + T: Borrow>, + { + todo!() + } +} + impl ToBytesGadget for G2PreparedGadget

{ #[inline] fn to_bytes>( @@ -310,6 +430,55 @@ pub struct AteDoubleCoefficientsGadget { pub c_l: Fp3Gadget, } +impl AllocGadget, P::Fp> + for AteDoubleCoefficientsGadget

+{ + fn alloc_constant>( + mut cs: CS, + t: T, + ) -> Result + where + T: Borrow>, + { + let obj = t.borrow(); + + let c_h_gadget = + Fp3Gadget::::alloc_constant(&mut cs.ns(|| "c_h"), &obj.c_h)?; + let c_4c_gadget = + Fp3Gadget::::alloc_constant(&mut cs.ns(|| "c_4c"), &obj.c_4c)?; + let c_j_gadget = + Fp3Gadget::::alloc_constant(&mut cs.ns(|| "c_j"), &obj.c_j)?; + let c_l_gadget = + Fp3Gadget::::alloc_constant(&mut cs.ns(|| "c_l"), &obj.c_l)?; + + Ok(Self { + c_h: c_h_gadget, + c_4c: c_4c_gadget, + c_j: c_j_gadget, + c_l: c_l_gadget, + }) + } + + fn alloc>(_cs: CS, _f: F) -> Result + where + F: FnOnce() -> Result, + T: Borrow>, + { + todo!() + } + + fn alloc_input>( + _cs: CS, + _f: F, + ) -> Result + where + F: FnOnce() -> Result, + T: Borrow>, + { + todo!() + } +} + impl ToBytesGadget for AteDoubleCoefficientsGadget

{ #[inline] fn to_bytes>( @@ -377,6 +546,44 @@ pub struct AteAdditionCoefficientsGadget { pub c_rz: Fp3Gadget, } +impl AllocGadget, P::Fp> + for AteAdditionCoefficientsGadget

+{ + fn alloc_constant>( + mut cs: CS, + t: T, + ) -> Result + where + T: Borrow>, + { + let t = t.borrow(); + + let c_l1 = Fp3Gadget::alloc_constant(&mut cs.ns(|| "c_l1"), &t.c_l1)?; + let c_rz = Fp3Gadget::alloc_constant(&mut cs.ns(|| "c_rz"), &t.c_rz)?; + + Ok(Self { c_l1, c_rz }) + } + + fn alloc>(_cs: CS, _f: F) -> Result + where + F: FnOnce() -> Result, + T: Borrow>, + { + todo!() + } + + fn alloc_input>( + _cs: CS, + _f: F, + ) -> Result + where + F: FnOnce() -> Result, + T: Borrow>, + { + todo!() + } +} + impl ToBytesGadget for AteAdditionCoefficientsGadget

{ #[inline] fn to_bytes>( diff --git a/r1cs-std/src/groups/curves/short_weierstrass/mod.rs b/r1cs-std/src/groups/curves/short_weierstrass/mod.rs index 4c2e725..5ab7d35 100644 --- a/r1cs-std/src/groups/curves/short_weierstrass/mod.rs +++ b/r1cs-std/src/groups/curves/short_weierstrass/mod.rs @@ -29,6 +29,33 @@ pub struct AffineGadget< _engine: PhantomData, } +impl< + P: SWModelParameters, + ConstraintF: PrimeField, + F: FieldGadget + ToConstraintFieldGadget, + > ToConstraintFieldGadget for AffineGadget +{ + fn to_constraint_field>( + &self, + mut cs: CS, + ) -> Result>, SynthesisError> { + let mut res = Vec::new(); + + let mut x_gadget = self.x.to_constraint_field(&mut cs.ns(|| "x"))?; + let mut y_gadget = self.y.to_constraint_field(&mut cs.ns(|| "y"))?; + + let mut infinity_gadget = self + .infinity + .to_constraint_field(&mut cs.ns(|| "infinity"))?; + + res.append(&mut x_gadget); + res.append(&mut y_gadget); + res.append(&mut infinity_gadget); + + Ok(res) + } +} + impl> AffineGadget { diff --git a/r1cs-std/src/groups/curves/twisted_edwards/mod.rs b/r1cs-std/src/groups/curves/twisted_edwards/mod.rs index e926ddf..2def1c7 100644 --- a/r1cs-std/src/groups/curves/twisted_edwards/mod.rs +++ b/r1cs-std/src/groups/curves/twisted_edwards/mod.rs @@ -3,13 +3,14 @@ use algebra::{ twisted_edwards_extended::GroupAffine as TEAffine, MontgomeryModelParameters, TEModelParameters, }, - BitIterator, Field, One, Zero, + BitIterator, Field, One, PrimeField, Zero, }; use r1cs_core::{ConstraintSystem, SynthesisError}; use crate::{prelude::*, Vec}; +use crate::fields::fp::FpGadget; use core::{borrow::Borrow, marker::PhantomData}; #[derive(Derivative)] @@ -235,6 +236,28 @@ impl ToConstraintFieldGadget for AffineGadget +where + P: TEModelParameters, + ConstraintF: PrimeField, + F: FieldGadget + ToConstraintFieldGadget, +{ + fn to_constraint_field>( + &self, + mut cs: CS, + ) -> Result>, SynthesisError> { + let mut res = Vec::new(); + + let mut x_gadget = self.x.to_constraint_field(&mut cs.ns(|| "x"))?; + let mut y_gadget = self.y.to_constraint_field(&mut cs.ns(|| "y"))?; + + res.append(&mut x_gadget); + res.append(&mut y_gadget); + + Ok(res) + } +} + impl PartialEq for AffineGadget where P: TEModelParameters, @@ -1449,7 +1472,7 @@ where boolean::AllocatedBit, groups::test::group_test, prelude::*, test_constraint_system::TestConstraintSystem, }; - use algebra::{test_rng, Group, PrimeField, UniformRand}; + use algebra::{test_rng, Group, UniformRand}; use rand::Rng; group_test::, GG>(); diff --git a/r1cs-std/src/lib.rs b/r1cs-std/src/lib.rs index fba60f5..a60b98c 100644 --- a/r1cs-std/src/lib.rs +++ b/r1cs-std/src/lib.rs @@ -89,7 +89,7 @@ pub mod prelude { alloc::*, bits::{boolean::Boolean, uint32::UInt32, uint8::UInt8, ToBitsGadget, ToBytesGadget}, eq::*, - fields::FieldGadget, + fields::{fp::FpGadget, FieldGadget, ToConstraintFieldGadget}, groups::GroupGadget, instantiated::*, pairing::PairingGadget, diff --git a/r1cs-std/src/pairing/mod.rs b/r1cs-std/src/pairing/mod.rs index 7cce2cb..ef700f9 100644 --- a/r1cs-std/src/pairing/mod.rs +++ b/r1cs-std/src/pairing/mod.rs @@ -10,8 +10,14 @@ pub mod mnt6; pub trait PairingGadget { type G1Gadget: GroupGadget; type G2Gadget: GroupGadget; - type G1PreparedGadget: ToBytesGadget + Clone + Debug; - type G2PreparedGadget: ToBytesGadget + Clone + Debug; + type G1PreparedGadget: AllocGadget + + ToBytesGadget + + Clone + + Debug; + type G2PreparedGadget: AllocGadget + + ToBytesGadget + + Clone + + Debug; type GTGadget: FieldGadget + Clone; fn miller_loop>(