use algebra::{groups::Group, Field}; use r1cs_core::{ConstraintSystem, SynthesisError}; use r1cs_std::prelude::*; use crate::signature::SigRandomizePkGadget; use core::{borrow::Borrow, marker::PhantomData}; use crate::signature::schnorr::{SchnorrPublicKey, SchnorrSigParameters, SchnorrSignature}; use digest::Digest; pub struct SchnorrSigGadgetParameters> { generator: GG, _group: PhantomData<*const G>, _engine: PhantomData<*const ConstraintF>, } impl> Clone for SchnorrSigGadgetParameters { fn clone(&self) -> Self { Self { generator: self.generator.clone(), _group: PhantomData, _engine: PhantomData, } } } #[derive(Derivative)] #[derivative( Debug(bound = "G: Group, ConstraintF: Field, GG: GroupGadget"), Clone(bound = "G: Group, ConstraintF: Field, GG: GroupGadget"), PartialEq(bound = "G: Group, ConstraintF: Field, GG: GroupGadget"), Eq(bound = "G: Group, ConstraintF: Field, GG: GroupGadget") )] pub struct SchnorrSigGadgetPk> { pub_key: GG, #[doc(hidden)] _group: PhantomData<*const G>, #[doc(hidden)] _engine: PhantomData<*const ConstraintF>, } pub struct SchnorrRandomizePkGadget> { #[doc(hidden)] _group: PhantomData<*const G>, #[doc(hidden)] _group_gadget: PhantomData<*const GG>, #[doc(hidden)] _engine: PhantomData<*const ConstraintF>, } impl SigRandomizePkGadget, ConstraintF> for SchnorrRandomizePkGadget where G: Group, GG: GroupGadget, D: Digest + Send + Sync, ConstraintF: Field, { type ParametersGadget = SchnorrSigGadgetParameters; type PublicKeyGadget = SchnorrSigGadgetPk; fn check_randomization_gadget>( mut cs: CS, parameters: &Self::ParametersGadget, public_key: &Self::PublicKeyGadget, randomness: &[UInt8], ) -> Result { let base = parameters.generator.clone(); let randomness = randomness .iter() .flat_map(|b| b.into_bits_le()) .collect::>(); let rand_pk = base.mul_bits( &mut cs.ns(|| "Compute Randomizer"), &public_key.pub_key, randomness.iter(), )?; Ok(SchnorrSigGadgetPk { pub_key: rand_pk, _group: PhantomData, _engine: PhantomData, }) } } impl AllocGadget, ConstraintF> for SchnorrSigGadgetParameters where G: Group, ConstraintF: Field, GG: GroupGadget, D: Digest, { fn alloc>(cs: CS, f: F) -> Result where F: FnOnce() -> Result, T: Borrow>, { let generator = GG::alloc_checked(cs, || f().map(|pp| pp.borrow().generator))?; Ok(Self { generator, _engine: PhantomData, _group: PhantomData, }) } fn alloc_input>( cs: CS, f: F, ) -> Result where F: FnOnce() -> Result, T: Borrow>, { let generator = GG::alloc_input(cs, || f().map(|pp| pp.borrow().generator))?; Ok(Self { generator, _engine: PhantomData, _group: PhantomData, }) } } impl AllocGadget, ConstraintF> for SchnorrSigGadgetPk where G: Group, ConstraintF: Field, GG: GroupGadget, { fn alloc>(cs: CS, f: F) -> Result where F: FnOnce() -> Result, T: Borrow>, { let pub_key = GG::alloc_input(cs, || f().map(|pk| *pk.borrow()))?; Ok(Self { pub_key, _engine: PhantomData, _group: PhantomData, }) } fn alloc_input>( cs: CS, f: F, ) -> Result where F: FnOnce() -> Result, T: Borrow>, { let pub_key = GG::alloc_input(cs, || f().map(|pk| *pk.borrow()))?; Ok(Self { pub_key, _engine: PhantomData, _group: PhantomData, }) } } impl ConditionalEqGadget for SchnorrSigGadgetPk where G: Group, ConstraintF: Field, GG: GroupGadget, { #[inline] fn conditional_enforce_equal>( &self, mut cs: CS, other: &Self, condition: &Boolean, ) -> Result<(), SynthesisError> { self.pub_key.conditional_enforce_equal( &mut cs.ns(|| "PubKey equality"), &other.pub_key, condition, )?; Ok(()) } fn cost() -> usize { >::cost() } } impl EqGadget for SchnorrSigGadgetPk where G: Group, ConstraintF: Field, GG: GroupGadget, { } impl ToBytesGadget for SchnorrSigGadgetPk where G: Group, ConstraintF: Field, GG: GroupGadget, { fn to_bytes>( &self, mut cs: CS, ) -> Result, SynthesisError> { self.pub_key.to_bytes(&mut cs.ns(|| "PubKey To Bytes")) } fn to_bytes_strict>( &self, mut cs: CS, ) -> Result, SynthesisError> { self.pub_key .to_bytes_strict(&mut cs.ns(|| "PubKey To Bytes")) } }