crypto_bigint/modular/
prime_params.rs1use core::num::NonZeroU32;
4use ctutils::{CtAssignSlice, CtEqSlice, CtSelectUsingCtAssign};
5
6use super::{FixedMontyForm, FixedMontyParams};
7use crate::{Choice, CtAssign, CtEq, OddUint, Uint};
8
9#[cfg(feature = "subtle")]
10use crate::CtSelect;
11
12#[derive(Debug, Copy, Clone)]
15pub struct PrimeParams<const LIMBS: usize> {
16 pub(super) s: NonZeroU32,
18 pub(super) t: OddUint<LIMBS>,
20 pub(super) generator: NonZeroU32,
22 pub(super) sqrt_exp: Uint<LIMBS>,
24 pub(super) monty_root_unity: Uint<LIMBS>,
26 pub(super) monty_root_unity_p2: Uint<LIMBS>,
28}
29
30impl<const LIMBS: usize> PrimeParams<LIMBS> {
31 #[must_use]
37 #[allow(clippy::unwrap_in_result, clippy::missing_panics_doc)]
38 pub const fn new_vartime(params: &FixedMontyParams<LIMBS>, generator: u32) -> Self {
39 let p = params.modulus();
40 let p_minus_one = p.as_ref().set_bit_vartime(0, false);
41 let generator = NonZeroU32::new(generator).expect("invalid generator");
42 let s = NonZeroU32::new(p_minus_one.trailing_zeros_vartime()).expect("ensured non-zero");
43 let t = p
45 .as_ref()
46 .shr_vartime(s.get())
47 .to_odd()
48 .expect_copied("ensured odd");
49
50 let (exp, root) = if s.get() == 1 {
52 let exp = p.as_ref().shr_vartime(2).wrapping_add(&Uint::ONE);
54 let root = FixedMontyForm::new(&p_minus_one, params);
55 (exp, root)
56 } else {
57 let exp = t.as_ref().shr_vartime(1);
59 let root = FixedMontyForm::new(&Uint::from_u32(generator.get()), params)
61 .pow_vartime(t.as_ref());
62 let check = root.square_repeat_vartime(s.get() - 1);
64 assert!(
65 Uint::eq(&check.retrieve(), &p_minus_one).to_bool(),
66 "error calculating root of unity: invalid generator"
67 );
68 (exp, root)
69 };
70
71 Self {
72 s,
73 t,
74 generator,
75 sqrt_exp: exp,
76 monty_root_unity: root.to_montgomery(),
77 monty_root_unity_p2: root.square().to_montgomery(),
78 }
79 }
80
81 #[must_use]
83 pub const fn generator(&self) -> NonZeroU32 {
84 self.generator
85 }
86
87 #[must_use]
89 pub const fn s(&self) -> NonZeroU32 {
90 self.s
91 }
92
93 #[must_use]
95 pub const fn t(&self) -> OddUint<LIMBS> {
96 self.t
97 }
98}
99
100impl<const LIMBS: usize> CtAssign for PrimeParams<LIMBS> {
101 fn ct_assign(&mut self, other: &Self, choice: Choice) {
102 self.s.ct_assign(&other.s, choice);
103 self.generator.ct_assign(&other.generator, choice);
104 self.sqrt_exp.ct_assign(&other.sqrt_exp, choice);
105 self.monty_root_unity
106 .ct_assign(&other.monty_root_unity, choice);
107 self.monty_root_unity_p2
108 .ct_assign(&other.monty_root_unity_p2, choice);
109 }
110}
111impl<const LIMBS: usize> CtAssignSlice for PrimeParams<LIMBS> {}
112impl<const LIMBS: usize> CtSelectUsingCtAssign for PrimeParams<LIMBS> {}
113
114impl<const LIMBS: usize> CtEq for PrimeParams<LIMBS> {
115 fn ct_eq(&self, other: &Self) -> Choice {
116 self.s.ct_eq(&other.s)
117 & self.generator.ct_eq(&other.generator)
118 & self.sqrt_exp.ct_eq(&other.sqrt_exp)
119 & self.monty_root_unity.ct_eq(&other.monty_root_unity)
120 & self.monty_root_unity_p2.ct_eq(&other.monty_root_unity_p2)
121 }
122}
123impl<const LIMBS: usize> CtEqSlice for PrimeParams<LIMBS> {}
124
125#[cfg(feature = "subtle")]
126impl<const LIMBS: usize> subtle::ConstantTimeEq for PrimeParams<LIMBS> {
127 fn ct_eq(&self, other: &Self) -> subtle::Choice {
128 CtEq::ct_eq(self, other).into()
129 }
130}
131
132#[cfg(feature = "subtle")]
133impl<const LIMBS: usize> subtle::ConditionallySelectable for PrimeParams<LIMBS> {
134 fn conditional_assign(&mut self, src: &Self, choice: subtle::Choice) {
135 self.ct_assign(src, choice.into());
136 }
137
138 fn conditional_select(a: &Self, b: &Self, choice: subtle::Choice) -> Self {
139 a.ct_select(b, choice.into())
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use super::PrimeParams;
146 use crate::{Choice, CtEq, CtSelect, Odd, U128, modular::MontyParams};
147
148 #[test]
149 fn check_expected() {
150 let monty_params =
151 MontyParams::new_vartime(Odd::<U128>::from_be_hex("e38af050d74b8567f73c8713cbc7bc47"));
152 let prime_params = PrimeParams::new_vartime(&monty_params, 5);
153 assert_eq!(prime_params.s.get(), 1);
154 assert_eq!(prime_params.generator.get(), 5);
155 }
156
157 #[should_panic]
158 #[test]
159 fn check_invalid_generator() {
160 let monty_params =
161 MontyParams::new_vartime(Odd::<U128>::from_be_hex("e38af050d74b8567f73c8713cbc7bc47"));
162 let _ = PrimeParams::new_vartime(&monty_params, 0);
163 }
164
165 #[should_panic]
166 #[test]
167 fn check_non_prime() {
168 let monty_params =
169 MontyParams::new_vartime(Odd::<U128>::from_be_hex("e38af050d74b8567f73c8713cbc7bc01"));
170 let _ = PrimeParams::new_vartime(&monty_params, 5);
171 }
172
173 #[test]
174 fn check_equality() {
175 let monty_params_1 =
176 MontyParams::new_vartime(Odd::<U128>::from_be_hex("e38af050d74b8567f73c8713cbc7bc47"));
177 let prime_params_1 = PrimeParams::new_vartime(&monty_params_1, 5);
178
179 let monty_params_2 =
180 MontyParams::new_vartime(Odd::<U128>::from_be_hex("f2799d643ab7ff983437c3a86cdb1beb"));
181 let prime_params_2 = PrimeParams::new_vartime(&monty_params_2, 5);
182
183 assert!(CtEq::ct_eq(&prime_params_1, &prime_params_1).to_bool());
184 #[cfg(feature = "subtle")]
185 assert!(bool::from(subtle::ConstantTimeEq::ct_eq(
186 &prime_params_1,
187 &prime_params_1
188 )));
189
190 assert!(CtEq::ct_ne(&prime_params_1, &prime_params_2).to_bool());
191 #[cfg(feature = "subtle")]
192 assert!(bool::from(subtle::ConstantTimeEq::ct_ne(
193 &prime_params_1,
194 &prime_params_2
195 )));
196
197 assert!(
198 CtEq::ct_eq(
199 &CtSelect::ct_select(&prime_params_1, &prime_params_2, Choice::FALSE),
200 &prime_params_1,
201 )
202 .to_bool()
203 );
204 #[cfg(feature = "subtle")]
205 assert!(
206 CtEq::ct_eq(
207 &subtle::ConditionallySelectable::conditional_select(
208 &prime_params_1,
209 &prime_params_2,
210 subtle::Choice::from(0u8)
211 ),
212 &prime_params_1,
213 )
214 .to_bool()
215 );
216
217 assert!(
218 CtEq::ct_eq(
219 &CtSelect::ct_select(&prime_params_1, &prime_params_2, Choice::TRUE),
220 &prime_params_2,
221 )
222 .to_bool()
223 );
224 #[cfg(feature = "subtle")]
225 assert!(
226 CtEq::ct_eq(
227 &subtle::ConditionallySelectable::conditional_select(
228 &prime_params_1,
229 &prime_params_2,
230 subtle::Choice::from(1u8)
231 ),
232 &prime_params_2,
233 )
234 .to_bool()
235 );
236 }
237}