ark-ec-blind-signatures/src/lib.rs
src/lib.rsRaw
1#![allow(non_snake_case)]
2#![allow(clippy::many_single_char_names)]
3
4// #[cfg(feature="r1cs")]
5pub mod constraints;
6
7use ark_ec::{
8 models::twisted_edwards_extended::GroupAffine, AffineCurve, ProjectiveCurve, TEModelParameters,
9};
10
11use ark_ff::{
12 to_bytes, BigInteger, BigInteger256, Field, Fp256, FpParameters, FromBytes, One, PrimeField,
13 Zero,
14};
15
16use ark_std::marker::PhantomData;
17use ark_std::rand::{CryptoRng, RngCore};
18use ark_std::{ops::Mul, rand::Rng, UniformRand};
19use derivative::Derivative;
20
21// hash
22use arkworks_native_gadgets::poseidon;
23use arkworks_native_gadgets::poseidon::FieldHasher;
24use arkworks_utils::{
25 bytes_matrix_to_f, bytes_vec_to_f, parse_vec, poseidon_params::setup_poseidon_params, Curve,
26};
27
28// WIP
29use ark_ed_on_bn254::{
30 EdwardsAffine, EdwardsParameters, EdwardsProjective, FqParameters, Fr, FrParameters,
31};
32
33pub type ConstraintF<C> = <<C as ProjectiveCurve>::BaseField as Field>::BasePrimeField;
34pub type SecretKey<C> = <C as ProjectiveCurve>::ScalarField;
35pub type PublicKey<C> = <C as ProjectiveCurve>::Affine;
36pub type BlindedSignature<C> = <C as ProjectiveCurve>::ScalarField;
37
38// #[derive(Derivative)]
39#[derive(Clone, Default, Debug)]
40pub struct Signature<C: ProjectiveCurve> {
41 s: C::ScalarField, // ScalarField == Fr
42 r: <C as ProjectiveCurve>::Affine,
43}
44
45#[derive(Debug)]
46pub struct UserSecretData<C: ProjectiveCurve> {
47 a: C::ScalarField,
48 b: C::ScalarField,
49 r: C::Affine,
50}
51impl<C: ProjectiveCurve> UserSecretData<C> {
52 fn new_empty(parameters: &Parameters<C>) -> Self {
53 UserSecretData {
54 a: C::ScalarField::from(0 as u32),
55 b: C::ScalarField::from(0 as u32),
56 r: parameters.generator, // WIP
57 }
58 }
59}
60
61#[derive(Derivative)]
62#[derivative(Clone(bound = "C: ProjectiveCurve"), Debug)]
63pub struct Parameters<C: ProjectiveCurve> {
64 pub generator: C::Affine,
65}
66
67pub struct BlindSigScheme<C: ProjectiveCurve> {
68 _group: PhantomData<C>,
69}
70
71impl<C: ProjectiveCurve> BlindSigScheme<C>
72where
73 C::ScalarField: PrimeField,
74 GroupAffine<EdwardsParameters>: From<<C as ProjectiveCurve>::Affine>, // WIP
75{
76 pub fn setup() -> Parameters<C> {
77 let generator = C::prime_subgroup_generator().into();
78 Parameters { generator }
79 }
80
81 // signer
82 pub fn keygen<R: Rng>(parameters: &Parameters<C>, rng: &mut R) -> (PublicKey<C>, SecretKey<C>) {
83 let secret_key = C::ScalarField::rand(rng);
84 let public_key = parameters.generator.mul(secret_key).into();
85 (public_key, secret_key)
86 }
87
88 pub fn new_request_params<R: Rng>(
89 parameters: &Parameters<C>,
90 rng: &mut R,
91 ) -> (C::ScalarField, C::Affine) {
92 let k = C::ScalarField::rand(rng);
93 let R = parameters.generator.mul(k).into();
94 (k, R)
95 }
96
97 pub fn blind_sign(
98 sk: SecretKey<C>,
99 k: C::ScalarField,
100 m_blinded: C::ScalarField,
101 ) -> BlindedSignature<C> {
102 sk * m_blinded + k
103 }
104
105 // requester
106 pub fn new_blind_params<R: Rng>(
107 parameters: &Parameters<C>,
108 rng: &mut R,
109 signer_r: C::Affine,
110 ) -> UserSecretData<C>
111 where
112 <C as ProjectiveCurve>::ScalarField: From<BigInteger256>,
113 {
114 let mut u: UserSecretData<C> = UserSecretData::new_empty(parameters);
115 u.a = C::ScalarField::rand(rng);
116 u.b = C::ScalarField::rand(rng);
117
118 // R = aR' + bG
119 let aR = signer_r.mul(u.a.into_repr());
120 let bG = parameters.generator.mul(u.b.into_repr());
121 u.r = aR.into_affine() + bG.into_affine();
122
123 let r = EdwardsAffine::from(u.r); // WIP
124 let one = BigInteger256::from(1u64);
125 let x_repr = r.x.into_repr();
126 let modulus = <<C::ScalarField as PrimeField>::Params as FpParameters>::MODULUS;
127 let modulus_repr = BigInteger256::try_from(modulus.into()).unwrap();
128
129 if !(x_repr >= one && x_repr < modulus_repr) {
130 // TODO maybe add a counter of attempts with a limit
131 return Self::new_blind_params(parameters, rng, signer_r);
132 }
133 u
134 }
135
136 pub fn blind<R: Rng>(
137 parameters: &Parameters<C>,
138 rng: &mut R,
139 poseidon_hash: &poseidon::Poseidon<ConstraintF<C>>,
140 m: ConstraintF<C>,
141 signer_r: C::Affine,
142 ) -> Result<(C::ScalarField, UserSecretData<C>), ark_crypto_primitives::Error>
143 where
144 <C as ProjectiveCurve>::ScalarField: From<BigInteger256>,
145 {
146 let u = Self::new_blind_params(parameters, rng, signer_r);
147 // get X coordinate, as in new_blind_params we already checked that R.x is inside Fr and
148 // will not give None
149 let r = EdwardsAffine::from(u.r); // WIP
150 let x_fr = C::ScalarField::from(r.x.into_repr());
151
152 // m' = a^-1 rx h(m)
153 // TODO hash(m) must be \in Fr
154 let hm = poseidon_hash.hash(&[m])?;
155 // let hm_fr = C::ScalarField::from_repr(hm.into_repr()).unwrap();
156 let hm_fr = C::ScalarField::from_le_bytes_mod_order(&to_bytes!(hm)?); // WIP TMP
157 let m_blinded = C::ScalarField::from(u.a.inverse().unwrap() * x_fr) * hm_fr;
158
159 Ok((m_blinded, u))
160 }
161
162 pub fn unblind(s_blinded: C::ScalarField, u: UserSecretData<C>) -> Signature<C> {
163 // s = a s' + b
164 let s = u.a * s_blinded + u.b;
165 Signature { s, r: u.r }
166 }
167
168 pub fn verify(
169 parameters: &Parameters<C>,
170 poseidon_hash: &poseidon::Poseidon<ConstraintF<C>>,
171 m: ConstraintF<C>,
172 s: Signature<C>,
173 q: PublicKey<C>,
174 ) -> bool
175 where
176 <C as ProjectiveCurve>::ScalarField: From<BigInteger256>,
177 {
178 let sG = parameters.generator.mul(s.s.into_repr());
179
180 // TODO the output of hash(m) must be \in Fr
181 let hm = poseidon_hash.hash(&[m]).unwrap();
182 // let hm_fr = C::ScalarField::from_repr(hm.into_repr()).unwrap();
183 let hm_fr = C::ScalarField::from_le_bytes_mod_order(&to_bytes!(hm).unwrap()); // WIP TMP
184
185 // check that s.R.x is in Fr
186 let r = EdwardsAffine::from(s.r); // WIP
187 let one = BigInteger256::from(1u64);
188 let x_repr = r.x.into_repr();
189 let modulus = <<C::ScalarField as PrimeField>::Params as FpParameters>::MODULUS;
190 let modulus_repr = BigInteger256::try_from(modulus.into()).unwrap();
191 if !(x_repr >= one && x_repr < modulus_repr) {
192 return false;
193 }
194 // get s.R.x
195 let x_fr = C::ScalarField::from(r.x.into_repr());
196 let right = s.r + q.mul((x_fr * hm_fr).into_repr()).into_affine();
197
198 sG.into_affine() == right
199 }
200}
201
202// poseidon
203pub fn poseidon_setup_params<F: PrimeField>(
204 curve: Curve,
205 exp: i8,
206 width: u8,
207) -> poseidon::PoseidonParameters<F> {
208 let pos_data = setup_poseidon_params(curve, exp, width).unwrap();
209
210 let mds_f = bytes_matrix_to_f(&pos_data.mds);
211 let rounds_f = bytes_vec_to_f(&pos_data.rounds);
212
213 poseidon::PoseidonParameters {
214 mds_matrix: mds_f,
215 round_keys: rounds_f,
216 full_rounds: pos_data.full_rounds,
217 partial_rounds: pos_data.partial_rounds,
218 sbox: poseidon::sbox::PoseidonSbox(pos_data.exp),
219 width: pos_data.width,
220 }
221}
222
223#[cfg(test)]
224mod tests {
225 use super::*;
226 pub type Fq = ark_ed_on_bn254::Fq; // base field
227 // pub type Fr = ark_ed_on_bn254::Fr; // scalar field
228
229 #[test]
230 fn test_blind_signature_flow_native() {
231 type S = BlindSigScheme<EdwardsProjective>;
232
233 let poseidon_params = poseidon_setup_params::<Fq>(Curve::Bn254, 5, 3);
234 let poseidon_hash = poseidon::Poseidon::new(poseidon_params);
235
236 let mut rng = ark_std::test_rng();
237
238 let params = S::setup();
239 let (pk, sk) = S::keygen(¶ms, &mut rng);
240
241 let (k, signer_r) = S::new_request_params(¶ms, &mut rng);
242 let m = Fq::from(1234);
243
244 let (m_blinded, u) = S::blind(¶ms, &mut rng, &poseidon_hash, m, signer_r).unwrap();
245
246 let s_blinded = S::blind_sign(sk, k, m_blinded);
247
248 let s = S::unblind(s_blinded, u);
249
250 let verified = S::verify(¶ms, &poseidon_hash, m, s, pk);
251 assert!(verified);
252 }
253}