1pub mod reed_solomon {
2 use crate::{
3 core::{
4 actually_used_field::ActuallyUsedField,
5 circuits::boolean::boolean_value::Boolean,
6 expressions::field_expr::FieldExpr,
7 global_value::value::FieldValue,
8 },
9 traits::{GreaterEqual, GreaterThan, Invert, Random, Reveal},
10 utils::field::BaseField,
11 };
12 use num_traits::ToPrimitive;
13 use std::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign};
14
15 #[derive(Debug)]
16 #[allow(dead_code)]
17 pub struct KeyRecoveryDesc {
18 pub n: usize,
19 pub k: usize,
20 pub d: usize,
21 }
22
23 impl KeyRecoveryDesc {
24 #[allow(dead_code)]
25 pub fn new(n: usize) -> Self {
26 let k = (n - 1) / 3 + 1;
27 Self { n, k, d: n - k + 1 }
28 }
29 }
30
31 #[derive(Clone, Debug, Default)]
37 pub struct KeyRecoveryReedSolomonInit;
38
39 #[allow(dead_code)]
40 impl KeyRecoveryReedSolomonInit {
41 pub fn compute_generator_polynomial<const D: usize, F: ActuallyUsedField>(
46 d: usize,
47 ) -> [F; D] {
48 let mut g = [F::from(0); D];
49 let mut alpha_pow_j = F::MULTIPLICATIVE_GENERATOR;
50 g[0] = -alpha_pow_j;
51 g[1] = F::from(1);
52 for _ in 0..d - 2 {
53 alpha_pow_j *= F::MULTIPLICATIVE_GENERATOR;
54 let mut tmp = g;
55 tmp.rotate_right(1);
56 for i in 0..D {
57 g[i] *= -alpha_pow_j;
58 g[i] += tmp[i];
59 }
60 }
61
62 g
63 }
64
65 pub fn encode<
78 const N: usize,
79 const D: usize,
80 B: Boolean,
81 T: Random
82 + Mul<T, Output = T>
83 + Sub<T, Output = T>
84 + AddAssign<T>
85 + SubAssign<T>
86 + GreaterEqual<T, Output = B>
87 + From<B>
88 + From<usize>
89 + Copy,
90 >(
91 val: T,
92 g: [T; D],
93 k: T,
94 ) -> [T; N] {
95 let mut p = vec![val];
99 for i in 0..N - D {
100 let r = T::from(T::from(i).lt(k - T::from(1))) * T::random();
101 p[0] -= r;
102 p.push(r);
103 }
104
105 let mut s = [T::from(0); N];
111 for i in 0..N {
112 for j in 0..=i {
113 if i - j < D && j < N - D + 1 {
114 s[i] += g[i - j] * p[j];
115 }
116 }
117 }
118
119 s
120 }
121 }
122
123 #[derive(Clone, Debug, Default)]
124 pub struct KeyRecoveryReedSolomonFinal;
125
126 #[allow(dead_code)]
127 impl KeyRecoveryReedSolomonFinal {
128 pub fn compute_syndromes<
131 const N: usize,
132 const DMINUSONE: usize,
133 F: ActuallyUsedField,
134 B: Boolean,
135 T: Mul<T, Output = T>
136 + AddAssign<T>
137 + MulAssign<T>
138 + GreaterEqual<T, Output = B>
139 + From<B>
140 + From<F>
141 + From<usize>
142 + Reveal
143 + Copy,
144 >(
145 r: [T; N],
146 d_minus_one: T,
147 ) -> [T; DMINUSONE] {
148 let mut syndromes = [r[0]; DMINUSONE];
150 let mut alpha_pow_j = F::MULTIPLICATIVE_GENERATOR;
151 for (j, syndrome) in syndromes.iter_mut().enumerate() {
152 let mut pow = alpha_pow_j;
153 for r_i in r.iter().skip(1) {
154 *syndrome += *r_i * T::from(pow);
155 pow *= alpha_pow_j;
156 }
157 *syndrome *= T::from(T::from(j).lt(d_minus_one));
159 alpha_pow_j *= F::MULTIPLICATIVE_GENERATOR;
160 }
161
162 syndromes.map(|syndrome| syndrome.reveal())
163 }
164
165 pub fn compute_errors<const N: usize, const DMINUSONE: usize>(
168 d_minus_one: FieldValue<BaseField>,
169 syndromes: [FieldValue<BaseField>; DMINUSONE],
170 ) -> [FieldValue<BaseField>; N] {
171 let mut errors = [FieldValue::from(0); N];
172 for (i, e) in errors.iter_mut().enumerate() {
173 *e = FieldValue::new(FieldExpr::KeyRecoveryComputeErrors(
174 d_minus_one,
175 syndromes.to_vec(),
176 i,
177 ));
178 }
179 errors
180 }
181
182 #[allow(non_snake_case)]
185 pub fn compute_errors_field<const N: usize, F: ActuallyUsedField>(
186 d_minus_one: F,
187 syndromes: Vec<F>,
188 ) -> [F; N] {
189 let d_minus_one = d_minus_one
190 .to_unsigned_number()
191 .to_usize()
192 .expect("d_minus_one way too large");
193 let syndromes = syndromes.into_iter().take(d_minus_one).collect::<Vec<F>>();
194
195 let mut C = vec![F::from(1)];
198 let mut B = vec![F::from(1)];
199 let mut L = 0usize;
200 let mut m = 1usize;
201 let mut b = F::from(1);
202 for n in 0..syndromes.len() {
203 let mut d = syndromes[n];
204 for i in 1..=L {
205 d += C[i] * syndromes[n - i];
206 }
207
208 if d.eq(&F::from(0)) {
209 m += 1;
210 } else if 2 * L <= n {
211 let T = C.clone();
212 C.resize((m + B.len()).max(C.len()), F::from(0));
213 let db_inv = d * b.invert(true);
215 for i in 0..B.len() {
216 C[m + i] -= db_inv * B[i];
217 }
218 L = n + 1 - L;
219 B = T;
220 b = d;
221 m = 1usize;
222 } else {
223 C.resize((m + B.len()).max(C.len()), F::from(0));
224 let db_inv = d * b.invert(true);
226 for i in 0..B.len() {
227 C[m + i] -= db_inv * B[i];
228 }
229 m += 1;
230 }
231 }
232 let mut alpha_pows = vec![F::from(1)];
237 for i in 0..L {
238 alpha_pows.push(alpha_pows[i] * F::MULTIPLICATIVE_GENERATOR);
239 }
240 let mut lambdas = C.iter().copied().rev().collect::<Vec<F>>();
241 let mut error_locations = vec![lambdas
242 .iter()
243 .copied()
244 .reduce(|a, b| a + b)
245 .unwrap()
246 .eq(&F::from(0))];
247 for _ in 0..N - 1 {
248 lambdas = lambdas
249 .iter()
250 .zip(alpha_pows.clone())
251 .map(|(lambda, pow)| *lambda * pow)
252 .collect::<Vec<F>>();
253 error_locations.push(
254 lambdas
255 .iter()
256 .copied()
257 .reduce(|a, b| a + b)
258 .unwrap()
259 .eq(&F::from(0)),
260 );
261 }
262
263 let Lambda_prime = C
265 .iter()
266 .enumerate()
267 .skip(1)
268 .map(|(i, lambda)| F::from(i as u64) * lambda)
269 .collect::<Vec<F>>();
270 let mut Omega = Vec::new();
271 for i in 0..L {
272 let mut omega_i = F::from(0);
273 for j in 0..=i {
274 if i - j < syndromes.len() && j < L + 1 {
275 omega_i += syndromes[i - j] * C[j];
276 }
277 }
278 Omega.push(omega_i);
279 }
280
281 fn eval_poly<F: ActuallyUsedField>(poly: Vec<F>, x: F) -> F {
282 let mut res = poly[0];
283 let mut pow = F::from(1);
284 for c in poly.into_iter().skip(1) {
285 pow *= x;
286 res += c * pow;
287 }
288 res
289 }
290
291 let mut errors = [F::from(0); N];
292 let mut pow = F::from(1);
293 for (i, e) in error_locations.into_iter().enumerate() {
294 if e {
295 let X_inv = pow.invert(true);
296 let num = eval_poly(Omega.clone(), X_inv);
297 let denom = eval_poly(Lambda_prime.clone(), X_inv);
298 errors[i] = -num * denom.invert(true);
300 }
301 pow *= F::MULTIPLICATIVE_GENERATOR;
302 }
303
304 errors
305 }
306
307 pub fn compute_scaled_polynomials<const K: usize, F: ActuallyUsedField>(
317 d: usize,
318 k: usize,
319 ) -> ([F; K], [F; K]) {
320 let alpha_pows = (0..d + k - 1)
321 .scan(F::from(1), |acc, _| {
322 *acc *= F::MULTIPLICATIVE_GENERATOR;
323 Some(*acc)
324 })
325 .collect::<Vec<F>>();
326 let mut scaled_polynomials = alpha_pows
328 .iter()
329 .copied()
330 .skip(d - 1)
331 .map(|x| {
332 let num = alpha_pows
334 .iter()
335 .copied()
336 .skip(d - 1)
337 .filter(|val| *val != x)
338 .map(|val| F::from(1) - val)
339 .reduce(|a, b| a * b)
340 .unwrap();
341 let denom = alpha_pows
343 .iter()
344 .copied()
345 .skip(d - 1)
346 .filter(|val| *val != x)
347 .map(|val| x - val)
348 .reduce(|a, b| a * b)
349 .unwrap();
350 let poly = num * denom.invert(true);
351 let g_at_alpha_pow = alpha_pows
352 .iter()
353 .copied()
354 .take(d - 1)
355 .map(|z| x - z)
356 .reduce(|a, b| a * b)
357 .unwrap();
358 poly * g_at_alpha_pow.invert(true)
359 })
360 .collect::<Vec<F>>();
361
362 let mut alpha_pows = alpha_pows.iter().copied().skip(d - 1).collect::<Vec<F>>();
365 alpha_pows.resize(K, F::from(0));
366 scaled_polynomials.resize(K, F::from(0));
367
368 (
369 alpha_pows.try_into().unwrap_or_else(|v: Vec<F>| {
370 panic!("Expected a Vec of length {} (found {})", K, v.len())
371 }),
372 scaled_polynomials.try_into().unwrap_or_else(|v: Vec<F>| {
373 panic!("Expected a Vec of length {} (found {})", K, v.len())
374 }),
375 )
376 }
377
378 pub fn subtract_errors<const N: usize, T: Sub<T, Output = T>>(
380 r: [T; N],
381 e: [T; N],
382 ) -> [T; N] {
383 r.into_iter()
384 .zip(e)
385 .map(|(coeff_r, coeff_e)| coeff_r - coeff_e)
386 .collect::<Vec<T>>()
387 .try_into()
388 .unwrap_or_else(|v: Vec<T>| {
389 panic!("Expected a Vec of length {} (found {})", N, v.len())
390 })
391 }
392
393 pub fn decode<
396 const N: usize,
397 const K: usize,
398 B: Boolean,
399 T: Mul<T, Output = T>
400 + MulAssign<T>
401 + Add<T, Output = T>
402 + AddAssign<T>
403 + GreaterThan<T, Output = B>
404 + From<usize>
405 + Copy,
406 >(
407 s: [T; N],
408 alpha_pows: [T; K],
409 scaled_polynomials: [T; K],
410 ) -> T {
411 let s_at_alpha_pows = alpha_pows
413 .into_iter()
414 .map(|alpha_pow_j| {
415 let mut pow = alpha_pow_j;
416 let mut s_at_alpha_pow = s[0];
417 for s_i in s.iter().skip(1) {
418 s_at_alpha_pow += *s_i * pow;
419 pow *= alpha_pow_j;
420 }
421 s_at_alpha_pow
422 })
423 .collect::<Vec<T>>();
424
425 scaled_polynomials
431 .into_iter()
432 .zip(s_at_alpha_pows)
433 .map(|(poly, s_at_alpha_pow)| poly * s_at_alpha_pow)
434 .reduce(|a, b| a + b)
435 .unwrap()
436 }
437 }
438}
439
440pub mod shamir {
441 use crate::{
442 core::{
443 actually_used_field::ActuallyUsedField,
444 bounds::FieldBounds,
445 circuits::{
446 boolean::boolean_value::{Boolean, BooleanValue},
447 traits::arithmetic_circuit::ArithmeticCircuit,
448 },
449 expressions::expr::EvalFailure,
450 global_value::value::FieldValue,
451 },
452 traits::{GreaterThan, Invert, Random},
453 utils::number::Number,
454 };
455 use rand::{seq::SliceRandom, thread_rng};
456 use std::ops::{Add, AddAssign, Mul, MulAssign};
457
458 #[derive(Clone, Debug, Default)]
459 pub struct KeyRecoveryShamirInit;
460
461 impl KeyRecoveryShamirInit {
462 pub fn shamir_secret_share<
466 const N: usize,
467 B: Boolean,
468 T: Random
469 + Mul<T, Output = T>
470 + MulAssign<T>
471 + AddAssign<T>
472 + GreaterThan<T, Output = B>
473 + From<B>
474 + From<usize>
475 + Copy,
476 >(
477 val: T,
478 deg: T,
479 n: T,
480 ) -> [T; N] {
481 let mut coeffs = vec![val];
482 coeffs.extend((0..N - 1).map(|_| T::random()));
483 (1..N + 1)
484 .map(|i| {
485 let mut res = T::from(0);
486 let mut pow = T::from(T::from(i).le(n));
490 coeffs.iter().enumerate().for_each(|(j, c)| {
491 res += pow * *c * T::from(T::from(j).le(deg));
492 pow *= T::from(i);
493 });
494 res
495 })
496 .collect::<Vec<T>>()
497 .try_into()
498 .unwrap_or_else(|v: Vec<T>| {
499 panic!("Expected a Vec of length {} (found {})", N, v.len())
500 })
501 }
502 }
503
504 #[derive(Clone, Debug, Default)]
505 pub struct KeyRecoveryShamirFinal;
506
507 impl KeyRecoveryShamirFinal {
508 pub fn lagrange_interpolate_at_zero<
509 const N: usize,
510 T: Mul<T, Output = T> + Add<T, Output = T> + From<usize> + Copy,
511 >(
512 inps: [(T, T); N],
513 ) -> T {
514 inps.into_iter()
515 .fold(T::from(0), |acc, (poly, y)| acc + y * poly)
516 }
517 }
518
519 #[derive(Clone, Debug)]
520 #[allow(dead_code)]
521 struct TestKeyRecovery {
522 deg: usize,
523 n: usize,
524 }
525
526 impl TestKeyRecovery {
527 #[allow(dead_code)]
528 pub fn new(deg: usize, n: usize) -> Self {
529 Self { deg, n }
530 }
531 }
532
533 const N: usize = 100;
534
535 impl<F: ActuallyUsedField> ArithmeticCircuit<F> for TestKeyRecovery {
536 fn eval(&self, x: Vec<F>) -> Result<Vec<F>, EvalFailure> {
537 if x.len() != 1 {
538 panic!("expected input of length 1 (found {})", x.len());
539 }
540 if self.n > N {
541 return EvalFailure::err_ub("n too large");
542 }
543 Ok(x)
544 }
545
546 fn bounds(&self, _bounds: Vec<FieldBounds<F>>) -> Vec<FieldBounds<F>> {
547 vec![FieldBounds::All]
548 }
549
550 fn run(&self, vals: Vec<FieldValue<F>>) -> Vec<FieldValue<F>>
551 where
552 F: ActuallyUsedField,
553 {
554 let all_secret_shares =
556 KeyRecoveryShamirInit::shamir_secret_share::<N, BooleanValue, FieldValue<F>>(
557 vals[0],
558 FieldValue::<F>::from(self.deg),
559 FieldValue::<F>::from(self.n),
560 );
561
562 let mut secret_shares = all_secret_shares
564 .into_iter()
565 .take(self.n)
566 .enumerate()
567 .map(|(i, secret_share)| (i + 1, secret_share))
568 .collect::<Vec<(usize, FieldValue<F>)>>();
569
570 let mut rng = thread_rng();
573 secret_shares.shuffle(&mut rng);
574 let secret_shares = secret_shares
575 .into_iter()
576 .take(self.deg + 1)
577 .collect::<Vec<(usize, FieldValue<F>)>>();
578
579 let (xs, mut ys): (Vec<usize>, Vec<FieldValue<F>>) =
581 secret_shares.iter().copied().unzip();
582 let mut lagrange_basis_polynomials = xs
583 .iter()
584 .copied()
585 .map(|x| {
586 let num = xs
587 .iter()
588 .copied()
589 .filter(|val| *val != x)
590 .map(|val| -Number::from(val))
591 .reduce(|a, b| a * b)
592 .unwrap();
593 let denom = xs
594 .iter()
595 .copied()
596 .filter(|val| *val != x)
597 .map(|val| Number::from(x) - Number::from(val))
598 .reduce(|a, b| a * b)
599 .unwrap();
600 FieldValue::from(F::from(num) * F::from(denom).invert(true))
601 })
602 .collect::<Vec<FieldValue<F>>>();
603 lagrange_basis_polynomials.extend(std::iter::repeat_n(
604 FieldValue::<F>::from(0),
605 N - (self.deg + 1),
606 ));
607 ys.extend(std::iter::repeat_n(
608 FieldValue::<F>::from(0),
609 N - (self.deg + 1),
610 ));
611
612 vec![KeyRecoveryShamirFinal::lagrange_interpolate_at_zero::<
614 N,
615 FieldValue<F>,
616 >(
617 lagrange_basis_polynomials
618 .into_iter()
619 .zip(ys)
620 .collect::<Vec<(FieldValue<F>, FieldValue<F>)>>()
621 .try_into()
622 .unwrap_or_else(|v: Vec<(FieldValue<F>, FieldValue<F>)>| {
623 panic!("Expected a Vec of length {} (found {})", N, v.len())
624 }),
625 )]
626 }
627 }
628
629 #[cfg(test)]
630 mod tests {
631 use super::*;
632 use crate::{
633 core::circuits::traits::arithmetic_circuit::tests::TestedArithmeticCircuit,
634 utils::field::BaseField,
635 };
636 use rand::Rng;
637
638 impl TestedArithmeticCircuit<BaseField> for TestKeyRecovery {
639 fn gen_desc<R: Rng + ?Sized>(rng: &mut R) -> Self {
640 let mut deg = 3;
641 while rng.gen_bool(0.75) {
642 deg += 1;
643 }
644 let mut n = deg + 1;
645 while rng.gen_bool(0.75) {
646 n += 1;
647 }
648 Self::new(deg as usize, n as usize)
649 }
650
651 fn gen_n_inputs<R: Rng + ?Sized>(&self, _rng: &mut R) -> usize {
652 1
653 }
654 }
655
656 #[test]
657 fn tested_recovery() {
658 TestKeyRecovery::test(2, 1)
659 }
660 }
661}