composite_modulus_proofs/
blum_integer.rs

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        // Create non-Blum primes. Proofs should fail for these
263        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    // TODO: Uncomment after optimizing prime-power check
299    // #[test]
300    // fn proof_with_2048_bit_primes() {
301    //     let (p, q) = get_2048_bit_safe_primes();
302    //     let primes = Primes::from_primes(p, q);
303    //     let num_iters = 10;
304    //     check_given_primes!(num_iters, U2048, primes);
305    // }
306}