composite_modulus_proofs/math/
misc.rs1use crypto_bigint::{
2 modular::{MontyForm, MontyParams},
3 Concat, Uint,
4};
5
6pub fn euler_totient<const PRIME_LIMBS: usize, const OUTPUT_LIMBS: usize>(
8 p: &Uint<PRIME_LIMBS>,
9 q: &Uint<PRIME_LIMBS>,
10) -> Uint<OUTPUT_LIMBS>
11where
12 Uint<PRIME_LIMBS>: Concat<Output = Uint<OUTPUT_LIMBS>>,
13{
14 p.wrapping_sub(&Uint::<PRIME_LIMBS>::ONE)
15 .widening_mul(&q.wrapping_sub(&Uint::<PRIME_LIMBS>::ONE))
16}
17
18pub fn crt_combine<const LIMBS: usize, const WIDE_LIMBS: usize>(
24 r_p: &Uint<LIMBS>,
25 r_q: &Uint<LIMBS>,
26 p_inv: MontyForm<LIMBS>,
27 p: &Uint<LIMBS>,
28 q_mtg: MontyParams<LIMBS>,
29) -> Uint<WIDE_LIMBS>
30where
31 Uint<LIMBS>: Concat<Output = Uint<WIDE_LIMBS>>,
32{
33 let diff = MontyForm::new(r_q, q_mtg) - MontyForm::new(r_p, q_mtg);
35 let t = (diff * p_inv).retrieve();
37 t.widening_mul(p) + r_p.resize()
39}
40
41pub fn is_3_mod_4<const LIMBS: usize>(p: &Uint<LIMBS>) -> bool {
43 p.as_limbs()[0].0 & 3 == 3
44}
45
46pub fn is_3_mod_8<const LIMBS: usize>(p: &Uint<LIMBS>) -> bool {
48 p.as_limbs()[0].0 & 7 == 3
49}
50
51pub fn is_5_mod_8<const LIMBS: usize>(p: &Uint<LIMBS>) -> bool {
53 p.as_limbs()[0].0 & 7 == 5
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59 use crypto_bigint::{Random, RandomMod, U128, U256, U64};
60 use crypto_primes::generate_prime_with_rng;
61 use rand_core::OsRng;
62
63 #[test]
64 fn check_mods() {
65 let mut rng = OsRng::default();
66 for _ in 0..1000 {
67 let a = U64::random(&mut rng);
68 let a_4 = a.rem(&U64::from(4u32).to_nz().unwrap());
69 let a_8 = a.rem(&U64::from(8u32).to_nz().unwrap());
70 if a_4 == U64::from(3u32) {
71 assert!(is_3_mod_4(&a));
72 }
73 if a_8 == U64::from(3u32) {
74 assert!(is_3_mod_8(&a));
75 }
76 if a_8 == U64::from(5u32) {
77 assert!(is_5_mod_8(&a));
78 }
79 }
80 }
81
82 #[test]
83 fn crt() {
84 let mut rng = OsRng::default();
85
86 macro_rules! check {
87 ( $prime_type:ident, $product_type:ident ) => {
88 let p = generate_prime_with_rng::<$prime_type>(&mut rng, $prime_type::BITS);
89 let q = generate_prime_with_rng::<$prime_type>(&mut rng, $prime_type::BITS);
90 let n = p.widening_mul(&q);
91 let q_mtg = MontyParams::new(q.to_odd().unwrap());
92 let p_inv = MontyForm::new(&p, q_mtg).inv().unwrap();
94 for _ in 0..100 {
95 let a = $product_type::random_mod(&mut rng, &n.to_nz().unwrap());
96 let a_p: $prime_type = a.rem(&p.resize().to_nz().unwrap()).resize();
98 let a_q: $prime_type = a.rem(&q.resize().to_nz().unwrap()).resize();
100 assert_eq!(
101 a,
102 crt_combine::<{ $prime_type::LIMBS }, { $product_type::LIMBS }>(
103 &a_p, &a_q, p_inv, &p, q_mtg
104 )
105 );
106 }
107 };
108 }
109 check!(U64, U128);
110 check!(U128, U256);
111 }
112}