ark-ec-blind-signatures/src/constraints.rs
src/constraints.rsRaw
1use crate::{Parameters, Signature};
2
3use ark_ec::{AffineCurve, ProjectiveCurve};
4use ark_ed_on_bn254::{constraints::EdwardsVar, EdwardsParameters, FqParameters};
5use ark_ff::{
6 fields::{Field, Fp256},
7 to_bytes, ToConstraintField,
8};
9use ark_r1cs_std::{
10 alloc::{AllocVar, AllocationMode},
11 bits::uint8::UInt8,
12 boolean::Boolean,
13 fields::fp::FpVar,
14 groups::{curves::twisted_edwards::AffineVar, GroupOpsBounds},
15 prelude::CurveVar,
16 ToBitsGadget,
17};
18use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, Namespace, SynthesisError};
19use ark_std::ops::Mul;
20
21use core::{borrow::Borrow, marker::PhantomData};
22use derivative::Derivative;
23
24// hash
25use arkworks_r1cs_gadgets::poseidon;
26use arkworks_r1cs_gadgets::poseidon::{FieldHasherGadget, PoseidonGadget};
27
28// type ConstraintF<C> = <<C as ProjectiveCurve>::BaseField as Field>::BasePrimeField;
29type ConstraintF<C> = <C as ProjectiveCurve>::ScalarField; // Fr
30
31#[derive(Derivative)]
32#[derivative(
33 Debug(bound = "C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>"),
34 Clone(bound = "C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>")
35)]
36pub struct PublicKeyVar<C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>>
37where
38 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
39{
40 pub_key: GC,
41 #[doc(hidden)]
42 _group: PhantomData<*const C>,
43}
44
45#[derive(Derivative)]
46#[derivative(
47 Debug(bound = "C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>"),
48 Clone(bound = "C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>")
49)]
50pub struct SignatureVar<C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>>
51where
52 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
53{
54 // s: FpVar<ConstraintF>,
55 // s: C::ScalarField,
56 s: Vec<UInt8<ConstraintF<C>>>,
57 r: GC,
58 _curve: PhantomData<C>,
59}
60
61impl<C, GC> AllocVar<Signature<C>, ConstraintF<C>> for SignatureVar<C, GC>
62where
63 C: ProjectiveCurve,
64 // TODO not sure on '+ AllocVarar'
65 GC: CurveVar<C, ConstraintF<C>> + AllocVar<GC, ConstraintF<C>>,
66 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
67{
68 fn new_variable<T: Borrow<Signature<C>>>(
69 cs: impl Into<Namespace<ConstraintF<C>>>,
70 f: impl FnOnce() -> Result<T, SynthesisError>,
71 mode: AllocationMode,
72 ) -> Result<Self, SynthesisError> {
73 f().and_then(|val| {
74 let cs = cs.into();
75 // let s = val.borrow().s;
76 let mut s = Vec::<UInt8<ConstraintF<C>>>::new();
77 let s_bytes = to_bytes![val.borrow().s].unwrap();
78 for i in 0..s_bytes.len() {
79 s.push(UInt8::<ConstraintF<C>>::new_variable(
80 cs.clone(),
81 || Ok(s_bytes[i].clone()),
82 mode,
83 )?);
84 }
85
86 let r = GC::new_variable(cs.clone(), || Ok(val.borrow().r), mode)?;
87
88 Ok(Self {
89 s: s, // TODO not sure of FpVar::Constant
90 r: r,
91 _curve: PhantomData,
92 })
93 })
94 }
95}
96
97#[derive(Clone)]
98pub struct ParametersVar<C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>>
99where
100 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
101{
102 generator: GC,
103 _curve: PhantomData<C>,
104}
105
106impl<C, GC> AllocVar<Parameters<C>, ConstraintF<C>> for ParametersVar<C, GC>
107where
108 C: ProjectiveCurve,
109 GC: CurveVar<C, ConstraintF<C>>,
110 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
111{
112 fn new_variable<T: Borrow<Parameters<C>>>(
113 cs: impl Into<Namespace<ConstraintF<C>>>,
114 f: impl FnOnce() -> Result<T, SynthesisError>,
115 mode: AllocationMode,
116 ) -> Result<Self, SynthesisError> {
117 f().and_then(|val| {
118 let cs = cs.into();
119 let generator = GC::new_variable(cs.clone(), || Ok(val.borrow().generator), mode)?;
120 Ok(Self {
121 generator,
122 _curve: PhantomData,
123 })
124 })
125 }
126}
127
128pub struct BlindSigVerifyGadget<C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>>
129where
130 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
131{
132 params: Parameters<C>,
133 // sig: Signature<C>,
134 _gc: PhantomData<GC>,
135}
136
137impl<C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>> BlindSigVerifyGadget<C, GC>
138where
139 C: ProjectiveCurve,
140 GC: CurveVar<C, ConstraintF<C>>,
141 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
142 ark_r1cs_std::groups::curves::twisted_edwards::AffineVar<
143 EdwardsParameters,
144 FpVar<Fp256<FqParameters>>,
145 >: From<GC>,
146 FpVar<<C as ProjectiveCurve>::ScalarField>: Mul<FpVar<Fp256<FqParameters>>>,
147 FpVar<<C as ProjectiveCurve>::ScalarField>: From<<C as ProjectiveCurve>::ScalarField>,
148{
149 fn verify(
150 parameters: &ParametersVar<C, GC>,
151 poseidon_hash: &PoseidonGadget<ConstraintF<C>>,
152 m: FpVar<ConstraintF<C>>,
153 s: &SignatureVar<C, GC>,
154 q: &PublicKeyVar<C, GC>,
155 ) -> Result<Boolean<ConstraintF<C>>, SynthesisError>
156 where
157 <C as ProjectiveCurve>::ScalarField: Iterator, // WIP
158 <C as ProjectiveCurve>::ScalarField: From<
159 <FpVar<<C as ProjectiveCurve>::ScalarField> as Mul<FpVar<Fp256<FqParameters>>>>::Output,
160 >,
161 {
162 let s_s = s.s.clone();
163
164 let sG = parameters
165 .generator
166 .scalar_mul_le(s_s.to_bits_le()?.iter())?;
167
168 // G * s == R + Q * (R.x * H(m))
169 // Note: in a circuit that aggregates multiple verifications, the hashing step could be
170 // done outside the signature verification, once for all 1 votes and once for all 0 votes,
171 // saving lots of constraints
172 let hm = poseidon_hash.hash(&[m])?;
173 let r = EdwardsVar::from(s.r.clone()); // WIP
174
175 let rx_hm: ConstraintF<C> = ConstraintF::<C>::from(hm * r.x);
176 let rx_hm_fp: FpVar<ConstraintF<C>> = FpVar::<ConstraintF<C>>::from(rx_hm);
177
178 let Q_rx_hm = q.pub_key.scalar_mul_le(rx_hm_fp.to_bits_le()?.iter())?;
179 let RHS = s.r.clone() + Q_rx_hm;
180
181 sG.is_eq(&RHS)
182 }
183}