curve25519_dalek/backend/serial/scalar_mul/
precomputed_straus.rs1#![allow(non_snake_case)]
13
14use alloc::vec::Vec;
15
16use core::borrow::Borrow;
17use core::cmp::Ordering;
18
19use crate::backend::serial::curve_models::{
20 AffineNielsPoint, CompletedPoint, ProjectiveNielsPoint, ProjectivePoint,
21};
22use crate::edwards::EdwardsPoint;
23use crate::scalar::Scalar;
24use crate::traits::Identity;
25use crate::traits::VartimePrecomputedMultiscalarMul;
26use crate::window::{NafLookupTable5, NafLookupTable8};
27
28#[allow(missing_docs)]
29pub struct VartimePrecomputedStraus {
30 static_lookup_tables: Vec<NafLookupTable8<AffineNielsPoint>>,
31}
32
33impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus {
34 type Point = EdwardsPoint;
35
36 fn new<I>(static_points: I) -> Self
37 where
38 I: IntoIterator,
39 I::Item: Borrow<Self::Point>,
40 {
41 Self {
42 static_lookup_tables: static_points
43 .into_iter()
44 .map(|P| NafLookupTable8::<AffineNielsPoint>::from(P.borrow()))
45 .collect(),
46 }
47 }
48
49 fn len(&self) -> usize {
50 self.static_lookup_tables.len()
51 }
52
53 fn is_empty(&self) -> bool {
54 self.static_lookup_tables.is_empty()
55 }
56
57 fn optional_mixed_multiscalar_mul<I, J, K>(
58 &self,
59 static_scalars: I,
60 dynamic_scalars: J,
61 dynamic_points: K,
62 ) -> Option<Self::Point>
63 where
64 I: IntoIterator,
65 I::Item: Borrow<Scalar>,
66 J: IntoIterator,
67 J::Item: Borrow<Scalar>,
68 K: IntoIterator<Item = Option<Self::Point>>,
69 {
70 let static_nafs = static_scalars
71 .into_iter()
72 .map(|c| c.borrow().non_adjacent_form(5))
73 .collect::<Vec<_>>();
74 let dynamic_nafs: Vec<_> = dynamic_scalars
75 .into_iter()
76 .map(|c| c.borrow().non_adjacent_form(5))
77 .collect::<Vec<_>>();
78
79 let dynamic_lookup_tables = dynamic_points
80 .into_iter()
81 .map(|P_opt| P_opt.map(|P| NafLookupTable5::<ProjectiveNielsPoint>::from(&P)))
82 .collect::<Option<Vec<_>>>()?;
83
84 let sp = self.static_lookup_tables.len();
85 let dp = dynamic_lookup_tables.len();
86 assert!(sp >= static_nafs.len());
87 assert_eq!(dp, dynamic_nafs.len());
88
89 let mut S = ProjectivePoint::identity();
93 for j in (0..256).rev() {
94 let mut R: CompletedPoint = S.double();
95
96 for i in 0..dp {
97 let t_ij = dynamic_nafs[i][j];
98 match t_ij.cmp(&0) {
99 Ordering::Greater => {
100 R = &R.as_extended() + &dynamic_lookup_tables[i].select(t_ij as usize)
101 }
102 Ordering::Less => {
103 R = &R.as_extended() - &dynamic_lookup_tables[i].select(-t_ij as usize)
104 }
105 Ordering::Equal => {}
106 }
107 }
108
109 #[allow(clippy::needless_range_loop)]
110 for i in 0..static_nafs.len() {
111 let t_ij = static_nafs[i][j];
112 match t_ij.cmp(&0) {
113 Ordering::Greater => {
114 R = &R.as_extended() + &self.static_lookup_tables[i].select(t_ij as usize)
115 }
116 Ordering::Less => {
117 R = &R.as_extended() - &self.static_lookup_tables[i].select(-t_ij as usize)
118 }
119 Ordering::Equal => {}
120 }
121 }
122
123 S = R.as_projective();
124 }
125
126 Some(S.as_extended())
127 }
128}