1use crate::{
2 blum_powers::ProofOfBlumPowers,
3 error::Error,
4 setup::{Modulus, Primes, PrimesWithPrecomp},
5 square_free::ProofSquareFree,
6};
7use ark_std::io::Write;
8use crypto_bigint::{modular::SafeGcdInverter, Concat, Odd, PrecomputeInverter, Split, Uint};
9use digest::{ExtendableOutput, Update};
10use rand_core::CryptoRngCore;
11
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct ProofOfBlumInteger<
14 const MODULUS_LIMBS: usize,
15 const NUM_CHALLENGES_SQR_FREE: usize,
16 const ALPHA: usize,
17 const KAPPA: usize,
18> {
19 pub square_free: ProofSquareFree<MODULUS_LIMBS, NUM_CHALLENGES_SQR_FREE, ALPHA, KAPPA>,
20 pub blum_powers: ProofOfBlumPowers<MODULUS_LIMBS, KAPPA>,
21}
22
23impl<
24 const MODULUS_LIMBS: usize,
25 const NUM_CHALLENGES_SQR_FREE: usize,
26 const ALPHA: usize,
27 const KAPPA: usize,
28 > ProofOfBlumInteger<MODULUS_LIMBS, NUM_CHALLENGES_SQR_FREE, ALPHA, KAPPA>
29{
30 pub fn new<
31 D: Default + Update + ExtendableOutput,
32 W: Write + AsRef<[u8]>,
33 const PRIME_LIMBS: usize,
34 const PRIME_UNSAT_LIMBS: usize,
35 const MODULUS_UNSAT_LIMBS: usize,
36 >(
37 primes: Primes<PRIME_LIMBS>,
38 modulus: &Modulus<MODULUS_LIMBS>,
39 nonce: &[u8],
40 transcript: &mut W,
41 ) -> Result<Self, Error>
42 where
43 Uint<PRIME_LIMBS>: Concat<Output = Uint<MODULUS_LIMBS>>,
44 Uint<MODULUS_LIMBS>: Split<Output = Uint<PRIME_LIMBS>>,
45 Odd<Uint<PRIME_LIMBS>>: PrecomputeInverter<
46 Inverter = SafeGcdInverter<PRIME_LIMBS, PRIME_UNSAT_LIMBS>,
47 Output = Uint<PRIME_LIMBS>,
48 >,
49 Odd<Uint<MODULUS_LIMBS>>:
50 PrecomputeInverter<Inverter = SafeGcdInverter<MODULUS_LIMBS, MODULUS_UNSAT_LIMBS>>,
51 {
52 let square_free =
53 ProofSquareFree::<MODULUS_LIMBS, NUM_CHALLENGES_SQR_FREE, ALPHA, KAPPA>::new::<
54 D,
55 W,
56 PRIME_LIMBS,
57 MODULUS_UNSAT_LIMBS,
58 >(primes.clone(), modulus, nonce, transcript)?;
59 let blum_powers =
60 ProofOfBlumPowers::<MODULUS_LIMBS, KAPPA>::new::<D, W, PRIME_LIMBS, PRIME_UNSAT_LIMBS>(
61 primes, modulus, nonce, transcript,
62 )?;
63 Ok(Self {
64 square_free,
65 blum_powers,
66 })
67 }
68
69 pub fn new_given_precomputation<
70 D: Default + Update + ExtendableOutput,
71 W: Write + AsRef<[u8]>,
72 const PRIME_LIMBS: usize,
73 >(
74 primes: PrimesWithPrecomp<PRIME_LIMBS, MODULUS_LIMBS>,
75 modulus: &Modulus<MODULUS_LIMBS>,
76 nonce: &[u8],
77 transcript: &mut W,
78 ) -> Result<Self, Error>
79 where
80 Uint<PRIME_LIMBS>: Concat<Output = Uint<MODULUS_LIMBS>>,
81 Uint<MODULUS_LIMBS>: Split<Output = Uint<PRIME_LIMBS>>,
82 {
83 let square_free = ProofSquareFree::<MODULUS_LIMBS, NUM_CHALLENGES_SQR_FREE, ALPHA, KAPPA>::new_given_precomputation::<
84 D,
85 W,
86 PRIME_LIMBS,
87 >(
88 primes.clone(),
89 modulus,
90 nonce,
91 transcript,
92 )?;
93 let blum_powers = ProofOfBlumPowers::<MODULUS_LIMBS, KAPPA>::new_given_precomputation::<
94 D,
95 W,
96 PRIME_LIMBS,
97 >(primes, modulus, nonce, transcript)?;
98 Ok(Self {
99 square_free,
100 blum_powers,
101 })
102 }
103
104 pub fn num_responses_for_square_free_protocol(&self) -> usize {
105 self.square_free.num_responses()
106 }
107
108 pub fn num_responses_for_blum_powers_protocol(&self) -> usize {
109 self.blum_powers.num_responses()
110 }
111
112 pub fn num_responses(&self) -> usize {
113 self.square_free.num_responses() + self.blum_powers.num_responses()
114 }
115
116 pub fn verify<
117 R: CryptoRngCore,
118 D: Default + Update + ExtendableOutput,
119 W: Write + AsRef<[u8]>,
120 >(
121 &self,
122 rng: &mut R,
123 modulus: &Modulus<MODULUS_LIMBS>,
124 nonce: &[u8],
125 transcript: &mut W,
126 ) -> Result<(), Error> {
127 self.square_free
128 .verify::<D, W>(modulus, nonce, transcript)?;
129 self.blum_powers
130 .verify::<R, D, W>(rng, modulus, nonce, transcript)?;
131 Ok(())
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138 use crate::{math::misc::is_3_mod_4, safegcd_nlimbs, util::timing_info};
139 use crypto_bigint::{U256, U64};
140 use rand_core::OsRng;
141 use sha3::Shake256;
142 use std::time::Instant;
143
144 macro_rules! check_given_primes {
145 ( $num_iters: ident, $prime_type:ident, $primes: ident ) => {
146 const KAPPA: usize = 128;
147 const ALPHA: usize = 65537;
148 const NUM_CHALLENGES_SQR_FREE: usize =
149 crate::gcd_is_one::num_challenges::<ALPHA, KAPPA>() as usize;
150 const NUM_CHALLENGES_M2: usize =
151 crate::two_prime_divisors::num_challenges::<KAPPA>() as usize;
152
153 const PRIME_LIMBS: usize = $prime_type::LIMBS;
154 const PRIME_UNSAT_LIMBS: usize = safegcd_nlimbs!(Uint::<PRIME_LIMBS>::BITS as usize);
155 const MODULUS_LIMBS: usize = PRIME_LIMBS * 2;
156 const MODULUS_UNSAT_LIMBS: usize =
157 safegcd_nlimbs!(Uint::<MODULUS_LIMBS>::BITS as usize);
158
159 let mut rng = OsRng::default();
160 let modulus = Modulus::<MODULUS_LIMBS>::new(&$primes);
161 let primes_with_crt =
162 PrimesWithPrecomp::<PRIME_LIMBS, MODULUS_LIMBS>::from($primes.clone());
163 let nonce = b"123";
164
165 let mut prove_times = vec![];
166 let mut prove_with_precomp_times = vec![];
167 let mut ver_times = vec![];
168
169 println!(
170 "Running {} iterations for {} bits prime - {} challenges for {} bits of security",
171 $num_iters,
172 $prime_type::BITS,
173 NUM_CHALLENGES_M2,
174 KAPPA
175 );
176 for _ in 0..$num_iters {
177 let mut transcript = vec![];
178 let start = Instant::now();
179 let proof = ProofOfBlumInteger::<
180 MODULUS_LIMBS,
181 NUM_CHALLENGES_SQR_FREE,
182 ALPHA,
183 KAPPA,
184 >::new::<Shake256, _, PRIME_LIMBS, PRIME_UNSAT_LIMBS, MODULUS_UNSAT_LIMBS>(
185 $primes.clone(),
186 &modulus,
187 nonce,
188 &mut transcript,
189 )
190 .unwrap();
191 prove_times.push(start.elapsed());
192
193 assert_eq!(
194 proof.num_responses_for_square_free_protocol(),
195 NUM_CHALLENGES_SQR_FREE
196 );
197 assert_eq!(
198 proof.num_responses_for_blum_powers_protocol(),
199 NUM_CHALLENGES_M2
200 );
201 assert_eq!(
202 proof.num_responses(),
203 NUM_CHALLENGES_SQR_FREE + NUM_CHALLENGES_M2
204 );
205
206 let mut transcript = vec![];
207 let start = Instant::now();
208 proof
209 .verify::<OsRng, Shake256, _>(&mut rng, &modulus, nonce, &mut transcript)
210 .unwrap();
211 ver_times.push(start.elapsed());
212
213 let mut transcript = vec![];
214 let start = Instant::now();
215 let proof = ProofOfBlumInteger::<
216 MODULUS_LIMBS,
217 NUM_CHALLENGES_SQR_FREE,
218 ALPHA,
219 KAPPA,
220 >::new_given_precomputation::<Shake256, _, PRIME_LIMBS>(
221 primes_with_crt.clone(),
222 &modulus,
223 nonce,
224 &mut transcript,
225 )
226 .unwrap();
227 prove_with_precomp_times.push(start.elapsed());
228
229 let mut transcript = vec![];
230 let start = Instant::now();
231 proof
232 .verify::<OsRng, Shake256, _>(&mut rng, &modulus, nonce, &mut transcript)
233 .unwrap();
234 ver_times.push(start.elapsed());
235 }
236
237 println!("Proving time: {:?}", timing_info(prove_times));
238 println!(
239 "Proving time with precomputation: {:?}",
240 timing_info(prove_with_precomp_times)
241 );
242 println!("Verification time: {:?}", timing_info(ver_times));
243 };
244 }
245
246 #[test]
247 fn bad_proof() {
248 const KAPPA: usize = 128;
249 const ALPHA: usize = 65537;
250 const NUM_CHALLENGES_SQR_FREE: usize =
251 crate::gcd_is_one::num_challenges::<ALPHA, KAPPA>() as usize;
252
253 const PRIME_LIMBS: usize = U64::LIMBS;
254 const PRIME_UNSAT_LIMBS: usize = safegcd_nlimbs!(Uint::<PRIME_LIMBS>::BITS as usize);
255 const MODULUS_LIMBS: usize = PRIME_LIMBS * 2;
256 const MODULUS_UNSAT_LIMBS: usize = safegcd_nlimbs!(Uint::<MODULUS_LIMBS>::BITS as usize);
257
258 let mut rng = OsRng::default();
259 let blum_primes = Primes::<{ U64::LIMBS }>::new_with_blum_primes(&mut rng);
260 let modulus = Modulus::<MODULUS_LIMBS>::new(&blum_primes);
261
262 let non_blum_primes = {
264 let mut pr = Primes::<{ U64::LIMBS }>::new(&mut rng);
265 while is_3_mod_4(&pr.p) || is_3_mod_4(&pr.q) {
266 pr = Primes::<{ U64::LIMBS }>::new(&mut rng);
267 }
268 pr
269 };
270 let bad_modulus = Modulus::<MODULUS_LIMBS>::new(&non_blum_primes);
271 let nonce = b"123";
272
273 let mut transcript = vec![];
274 let proof =
275 ProofOfBlumInteger::<MODULUS_LIMBS, NUM_CHALLENGES_SQR_FREE, ALPHA, KAPPA>::new::<
276 Shake256,
277 _,
278 PRIME_LIMBS,
279 PRIME_UNSAT_LIMBS,
280 MODULUS_UNSAT_LIMBS,
281 >(blum_primes.clone(), &modulus, nonce, &mut transcript)
282 .unwrap();
283
284 let mut transcript = vec![];
285 assert!(proof
286 .verify::<OsRng, Shake256, _>(&mut rng, &bad_modulus, nonce, &mut transcript)
287 .is_err());
288 }
289
290 #[test]
291 fn proof() {
292 let mut rng = OsRng::default();
293 let primes = Primes::<{ U256::LIMBS }>::new_with_blum_primes(&mut rng);
294 let num_iters = 10;
295 check_given_primes!(num_iters, U256, primes);
296 }
297
298 }