use crate::signature::{
schnorr::{Parameters, PublicKey, Schnorr},
SigRandomizePkGadget,
};
use ark_ec::CurveGroup;
use ark_ff::Field;
use ark_r1cs_std::prelude::*;
use ark_relations::gr1cs::{Namespace, SynthesisError};
#[cfg(not(feature = "std"))]
use ark_std::vec::Vec;
use ark_std::{borrow::Borrow, marker::PhantomData};
use digest::Digest;
type ConstraintF<C> = <<C as CurveGroup>::BaseField as Field>::BasePrimeField;
#[derive(Clone)]
pub struct ParametersVar<C: CurveGroup, GC: CurveVar<C, ConstraintF<C>>>
where
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
{
generator: GC,
_curve: PhantomData<C>,
}
#[derive(Derivative)]
#[derivative(
Debug(bound = "C: CurveGroup, GC: CurveVar<C, ConstraintF<C>>"),
Clone(bound = "C: CurveGroup, GC: CurveVar<C, ConstraintF<C>>")
)]
pub struct PublicKeyVar<C: CurveGroup, GC: CurveVar<C, ConstraintF<C>>>
where
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
{
pub_key: GC,
#[doc(hidden)]
_group: PhantomData<*const C>,
}
pub struct SchnorrRandomizePkGadget<C: CurveGroup, GC: CurveVar<C, ConstraintF<C>>>
where
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
{
#[doc(hidden)]
_group: PhantomData<*const C>,
#[doc(hidden)]
_group_gadget: PhantomData<*const GC>,
}
impl<C, GC, D> SigRandomizePkGadget<Schnorr<C, D>, ConstraintF<C>>
for SchnorrRandomizePkGadget<C, GC>
where
C: CurveGroup,
GC: CurveVar<C, ConstraintF<C>>,
D: Digest + Send + Sync,
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
{
type ParametersVar = ParametersVar<C, GC>;
type PublicKeyVar = PublicKeyVar<C, GC>;
#[tracing::instrument(target = "gr1cs", skip(parameters, public_key, randomness))]
fn randomize(
parameters: &Self::ParametersVar,
public_key: &Self::PublicKeyVar,
randomness: &[UInt8<ConstraintF<C>>],
) -> Result<Self::PublicKeyVar, SynthesisError> {
let base = parameters.generator.clone();
let randomness = randomness
.iter()
.flat_map(|b| b.to_bits_le().unwrap())
.collect::<Vec<_>>();
let rand_pk = &public_key.pub_key + &base.scalar_mul_le(randomness.iter())?;
Ok(PublicKeyVar {
pub_key: rand_pk,
_group: PhantomData,
})
}
}
impl<C, GC, D> AllocVar<Parameters<C, D>, ConstraintF<C>> for ParametersVar<C, GC>
where
C: CurveGroup,
GC: CurveVar<C, ConstraintF<C>>,
D: Digest,
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
{
fn new_variable<T: Borrow<Parameters<C, D>>>(
cs: impl Into<Namespace<ConstraintF<C>>>,
f: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode,
) -> Result<Self, SynthesisError> {
let generator = GC::new_variable(cs, || f().map(|g| g.borrow().generator), mode)?;
Ok(Self {
generator,
_curve: PhantomData,
})
}
}
impl<C, GC> AllocVar<PublicKey<C>, ConstraintF<C>> for PublicKeyVar<C, GC>
where
C: CurveGroup,
GC: CurveVar<C, ConstraintF<C>>,
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
{
fn new_variable<T: Borrow<PublicKey<C>>>(
cs: impl Into<Namespace<ConstraintF<C>>>,
f: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode,
) -> Result<Self, SynthesisError> {
let pub_key = GC::new_variable(cs, f, mode)?;
Ok(Self {
pub_key,
_group: PhantomData,
})
}
}
impl<C, GC> EqGadget<ConstraintF<C>> for PublicKeyVar<C, GC>
where
C: CurveGroup,
GC: CurveVar<C, ConstraintF<C>>,
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
{
#[inline]
fn is_eq(&self, other: &Self) -> Result<Boolean<ConstraintF<C>>, SynthesisError> {
self.pub_key.is_eq(&other.pub_key)
}
#[inline]
fn conditional_enforce_equal(
&self,
other: &Self,
condition: &Boolean<ConstraintF<C>>,
) -> Result<(), SynthesisError> {
self.pub_key
.conditional_enforce_equal(&other.pub_key, condition)
}
#[inline]
fn conditional_enforce_not_equal(
&self,
other: &Self,
condition: &Boolean<ConstraintF<C>>,
) -> Result<(), SynthesisError> {
self.pub_key
.conditional_enforce_not_equal(&other.pub_key, condition)
}
}
impl<C, GC> ToBytesGadget<ConstraintF<C>> for PublicKeyVar<C, GC>
where
C: CurveGroup,
GC: CurveVar<C, ConstraintF<C>>,
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
{
fn to_bytes_le(&self) -> Result<Vec<UInt8<ConstraintF<C>>>, SynthesisError> {
self.pub_key.to_bytes_le()
}
}