structured_dstu4145/
validation.rs1use crate::{
4 Error, domains,
5 field::{Arithmetic, Polynomial},
6 multiplication::Kernel,
7 words::Words,
8};
9use core::fmt;
10use crypto_bigint::{
11 NonZero, Odd, U512,
12 modular::{FixedMontyForm, FixedMontyParams},
13};
14use rand_core::TryCryptoRng;
15
16type Monty = FixedMontyForm<{ U512::LIMBS }>;
17
18#[derive(Debug)]
20pub enum ValidationError<E> {
21 Input(Error),
23 Entropy(E),
25}
26
27impl<E: fmt::Display> fmt::Display for ValidationError<E> {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 match self {
30 Self::Input(error) => error.fmt(f),
31 Self::Entropy(error) => error.fmt(f),
32 }
33 }
34}
35
36impl<E: core::error::Error + 'static> core::error::Error for ValidationError<E> {
37 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
38 Some(match self {
39 Self::Input(error) => error,
40 Self::Entropy(error) => error,
41 })
42 }
43}
44
45impl<E> From<Error> for ValidationError<E> {
46 fn from(value: Error) -> Self {
47 Self::Input(value)
48 }
49}
50
51#[derive(Debug, Clone, Copy)]
54pub struct Factor<'a> {
55 pub prime: &'a [u8],
57 pub multiplicity: u16,
59}
60
61pub(crate) trait Validator {
62 type Error: From<Error>;
63 fn polynomial<K: Kernel>(
64 &mut self,
65 field: &Polynomial<K>,
66 terms: &[usize],
67 ) -> Result<(), Self::Error>;
68 fn order(&mut self, value: Words, degree: usize) -> Result<(), Self::Error>;
69}
70
71pub(crate) struct Known;
72
73pub(crate) fn standard_polynomial(degree: usize, terms: &[usize]) -> bool {
74 for row in domains::POLYNOMIALS {
75 if row[0] == degree {
76 let count = if row[2] == 0 { 1 } else { 3 };
77 return terms == &row[1..=count];
78 }
79 }
80 false
81}
82
83fn known_order(value: Words, degree: usize) -> bool {
84 domains::PB
85 .iter()
86 .any(|spec| spec.m == degree && spec.order == value)
87}
88
89impl Validator for Known {
90 type Error = Error;
91 fn polynomial<K: Kernel>(
92 &mut self,
93 field: &Polynomial<K>,
94 terms: &[usize],
95 ) -> Result<(), Error> {
96 if standard_polynomial(field.degree(), terms) {
97 Ok(())
98 } else {
99 Err(Error::ValidationEvidenceRequired)
100 }
101 }
102 fn order(&mut self, value: Words, degree: usize) -> Result<(), Error> {
103 if known_order(value, degree) {
104 Ok(())
105 } else {
106 Err(Error::ValidationEvidenceRequired)
107 }
108 }
109}
110
111pub(crate) struct Custom<'a, R> {
112 pub(crate) factors: &'a [Factor<'a>],
113 pub(crate) random: &'a mut R,
114}
115
116impl<R: TryCryptoRng> Validator for Custom<'_, R> {
117 type Error = ValidationError<R::Error>;
118
119 fn polynomial<K: Kernel>(
120 &mut self,
121 field: &Polynomial<K>,
122 terms: &[usize],
123 ) -> Result<(), Self::Error> {
124 let degree = field.degree();
125 if standard_polynomial(degree, terms) {
126 return Ok(());
127 }
128 if !domains::POLYNOMIALS.iter().any(|row| row[0] == degree) {
129 return Err(Error::UnsupportedDomain.into());
130 }
131 let mut polynomial_t = Words::ZERO;
132 polynomial_t.flip(1);
133 if field.square_times(polynomial_t, degree) != polynomial_t {
136 return Err(Error::InvalidField.into());
137 }
138 if self.factors.is_empty() || self.factors.len() > degree {
139 return Err(Error::ValidationEvidenceRequired.into());
140 }
141 let mut all_ones = Words([u64::MAX; 8]);
142 all_ones.clear_above(degree);
143 let mersenne = integer(all_ones);
144 let mut remaining = mersenne;
145 let mut previous = U512::ONE;
146 let mut multiplicities = 0;
147 for factor in self.factors {
148 multiplicities += usize::from(factor.multiplicity);
149 if factor.multiplicity == 0 || multiplicities > degree {
150 return Err(Error::InvalidField.into());
151 }
152 let prime = integer(Words::read(factor.prime, crate::ByteOrder::BigEndian)?);
153 if prime <= previous || !probable_prime(prime, self.random)? {
154 return Err(Error::InvalidField.into());
155 }
156 previous = prime;
157 let divisor =
158 Option::<NonZero<U512>>::from(NonZero::new(prime)).ok_or(Error::InvalidField)?;
159 for _ in 0..factor.multiplicity {
160 let (quotient, remainder) = remaining.div_rem_vartime(&divisor);
161 if remainder != U512::ZERO {
162 return Err(Error::InvalidField.into());
163 }
164 remaining = quotient;
165 }
166 let exponent = mersenne.div_rem_vartime(&divisor).0;
167 if power(field, polynomial_t, exponent) == Words::ONE {
168 return Err(Error::InvalidField.into());
169 }
170 }
171 if remaining != U512::ONE {
172 return Err(Error::ValidationEvidenceRequired.into());
173 }
174 Ok(())
175 }
176
177 fn order(&mut self, value: Words, degree: usize) -> Result<(), Self::Error> {
178 if known_order(value, degree) {
179 return Ok(());
180 }
181 let candidate = integer(value);
182 if !probable_prime(candidate, self.random)? {
183 return Err(Error::InvalidDomain.into());
184 }
185 let odd = Option::<Odd<U512>>::from(Odd::new(candidate)).ok_or(Error::InvalidDomain)?;
186 let params = FixedMontyParams::new_vartime(odd);
187 let two = Monty::new(&U512::from_u32(2), ¶ms);
188 let degree = u32::try_from(degree).map_err(|_| Error::UnsupportedDomain)?;
189 let step = two.pow_vartime(&U512::from_u32(degree));
190 let mut product = Monty::one(¶ms);
191 for _ in 0..32 {
192 product *= step;
193 if product.retrieve() == U512::ONE {
194 return Err(Error::InvalidDomain.into());
195 }
196 }
197 Ok(())
198 }
199}
200
201pub(crate) fn integer(value: Words) -> U512 {
202 let mut bytes = [0; 64];
203 for (chunk, limb) in bytes.as_chunks_mut::<8>().0.iter_mut().zip(value.0) {
204 chunk.copy_from_slice(&limb.to_le_bytes());
205 }
206 U512::from_le_slice(&bytes)
207}
208
209pub(crate) fn order_bounds(value: Words, degree: usize) -> Result<(), Error> {
210 if !value.bit(0) || value.bits() < 161 || value.bits() > degree + 1 {
211 return Err(Error::InvalidDomain);
212 }
213 let power = U512::ONE.shl_vartime(u32::try_from(degree).map_err(|_| Error::UnsupportedDomain)?);
215 let bound = power
216 .floor_sqrt_vartime()
217 .wrapping_add(&U512::ONE)
218 .shl_vartime(2);
219 if integer(value) < bound {
220 return Err(Error::InvalidDomain);
221 }
222 Ok(())
223}
224
225fn probable_prime<R: TryCryptoRng>(
226 candidate: U512,
227 random: &mut R,
228) -> Result<bool, ValidationError<R::Error>> {
229 for small in [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37] {
230 let prime = U512::from_u32(small);
231 if candidate == prime {
232 return Ok(true);
233 }
234 if candidate < prime {
235 return Ok(false);
236 }
237 let divisor =
238 Option::<NonZero<U512>>::from(NonZero::new(prime)).ok_or(Error::InvalidDomain)?;
239 if candidate.rem_vartime(&divisor) == U512::ZERO {
240 return Ok(false);
241 }
242 }
243 let odd = Option::<Odd<U512>>::from(Odd::new(candidate)).ok_or(Error::InvalidDomain)?;
244 let params = FixedMontyParams::new_vartime(odd);
245 let minus_one = candidate.wrapping_sub(&U512::ONE);
246 let twos = minus_one.trailing_zeros_vartime();
247 let exponent = minus_one.shr_vartime(twos);
248 let bits = candidate.bit_width_vartime();
249 let bytes = usize::try_from(bits.div_ceil(8)).map_err(|_| Error::InvalidDomain)?;
250 for _ in 0..50 {
253 let mut selected = None;
254 for _ in 0..128 {
255 let mut sample = [0; 64];
256 random
257 .try_fill_bytes(&mut sample[..bytes])
258 .map_err(ValidationError::Entropy)?;
259 if !bits.is_multiple_of(8) {
260 sample[bytes - 1] &= (1 << (bits % 8)) - 1;
261 }
262 let base = U512::from_le_slice(&sample);
263 if base > U512::ONE && base < candidate {
264 selected = Some(base);
265 break;
266 }
267 }
268 let base = selected.ok_or(Error::RandomSampleRefused)?;
269 let mut witness = Monty::new(&base, ¶ms).pow_vartime(&exponent);
270 let answer = witness.retrieve();
271 if answer == U512::ONE || answer == minus_one {
272 continue;
273 }
274 let mut passed = false;
275 for _ in 1..twos {
276 witness *= witness;
277 let answer = witness.retrieve();
278 if answer == minus_one {
279 passed = true;
280 break;
281 }
282 if answer == U512::ONE {
283 return Ok(false);
284 }
285 }
286 if !passed {
287 return Ok(false);
288 }
289 }
290 Ok(true)
291}
292
293fn power<F: Arithmetic>(field: &F, value: Words, exponent: U512) -> Words {
294 let bytes = exponent.to_le_bytes();
295 let mut result = field.one();
296 for bit in (0..exponent.bit_width_vartime()).rev() {
297 result = field.square(result);
298 let index = bit as usize;
299 if bytes[index / 8] & (1 << (index % 8)) != 0 {
300 result = field.multiply(result, value);
301 }
302 }
303 result
304}