airbender_crypto/secp256r1/
verify.rs1use super::{
2 context::{GeneratorMultiplesTable, TABLE_G},
3 points::Affine,
4 scalar::{Scalar, Signature},
5 wnaf::Wnaf,
6 Secp256r1Err, ECMULT_TABLE_SIZE_A, WINDOW_A, WINDOW_G,
7};
8use core::mem::MaybeUninit;
9
10type Jacobian = super::points::Jacobian;
11
12pub fn verify(
13 digest: &[u8; 32],
14 r: &[u8; 32],
15 s: &[u8; 32],
16 x: &[u8; 32],
17 y: &[u8; 32],
18) -> Result<bool, Secp256r1Err> {
19 let Signature { r, s } = Signature::from_scalars(r, s)?;
20 let pk = Affine::from_be_bytes(x, y)?
21 .reject_identity()?
22 .to_jacobian();
23 let z = Scalar::reduce_be_bytes(digest);
24 let mut s_inv = s;
25 s_inv.invert_assign();
26
27 let u1 = z * &s_inv;
28 let u2 = r * &s_inv;
29
30 let x = ecmult(pk, u2, u1, &TABLE_G)
31 .to_affine()
32 .reject_identity()?
33 .x;
34
35 let recovered = Scalar::reduce_be_bytes(&x.to_be_bytes());
36
37 let bool = r == recovered;
38 Ok(bool)
39}
40
41fn ecmult(a: Jacobian, na: Scalar, ng: Scalar, table_g: &GeneratorMultiplesTable) -> Jacobian {
42 let (wnaf_a, table_a) = if !na.is_zero() && !a.is_infinity() {
43 (Wnaf::new(na, WINDOW_A), OddMultiplesTable::from(&a))
44 } else {
45 (Wnaf::default(), OddMultiplesTable::default())
46 };
47
48 let wnaf_ng = if !ng.is_zero() {
49 Wnaf::new(ng, WINDOW_G)
50 } else {
51 Wnaf::default()
52 };
53
54 let bits = wnaf_a.bits().max(wnaf_ng.bits());
55 let mut r = Jacobian::default();
56
57 for i in (0..bits).rev() {
58 r.double_assign();
59
60 if let Some(n) = wnaf_a.get_digit(i) {
61 r.add_assign(&table_a.get(n, WINDOW_A));
62 }
63
64 if let Some(n) = wnaf_ng.get_digit(i) {
65 r.add_ge_assign(&table_g.get_ge(n, WINDOW_G));
66 }
67 }
68
69 r
70}
71
72#[derive(Default)]
73struct OddMultiplesTable([Jacobian; ECMULT_TABLE_SIZE_A]);
74
75impl OddMultiplesTable {
76 fn from(p: &Jacobian) -> Self {
77 debug_assert!(!p.is_infinity());
78
79 let mut table = [const { MaybeUninit::uninit() }; ECMULT_TABLE_SIZE_A];
80
81 let mut p = *p;
82 table[0].write(p);
83 let mut p_double = p;
84 p_double.double_assign();
85
86 for x in table.iter_mut().skip(1) {
87 p.add_assign(&p_double);
88 x.write(p);
89 }
90
91 Self(unsafe {
92 core::mem::transmute::<
93 [MaybeUninit<Jacobian>; ECMULT_TABLE_SIZE_A],
94 [Jacobian; ECMULT_TABLE_SIZE_A],
95 >(table)
96 })
97 }
98
99 fn get(&self, n: i32, w: usize) -> Jacobian {
100 debug_assert!(
101 (2..=31).contains(&w)
102 && ((n & 1) == 1)
103 && (n >= -((1 << (w - 1)) - 1))
104 && (n < (1 << (w - 1)))
105 );
106
107 if n > 0 {
108 self.0[(n - 1) as usize / 2]
109 } else {
110 -self.0[(-n - 1) as usize / 2]
111 }
112 }
113}
114
115#[cfg(test)]
116mod test {
117 use super::{ecmult, Scalar};
118
119 use crate::secp256r1::{
120 context::TABLE_G,
121 field::FieldElement,
122 points::{Jacobian, JacobianConst},
123 test_vectors::MUL_TEST_VECTORS,
124 };
125
126 #[test]
127 fn test_ecmult_mix() {
128 assert_eq!(
129 JacobianConst::GENERATOR.double().to_affine(),
130 ecmult(Jacobian::GENERATOR, Scalar::ONE, Scalar::ONE, &TABLE_G).to_affine()
131 );
132
133 assert_eq!(
134 JacobianConst::GENERATOR
135 .double()
136 .add(&JacobianConst::GENERATOR)
137 .to_affine(),
138 ecmult(
139 Jacobian::GENERATOR,
140 Scalar::from_words([2, 0, 0, 0]),
141 Scalar::ONE,
142 &TABLE_G
143 )
144 .to_affine()
145 );
146
147 assert_eq!(
148 JacobianConst::GENERATOR
149 .double()
150 .add(&JacobianConst::GENERATOR)
151 .to_affine(),
152 ecmult(
153 Jacobian::GENERATOR,
154 Scalar::ONE,
155 Scalar::from_words([2, 0, 0, 0]),
156 &TABLE_G
157 )
158 .to_affine()
159 );
160
161 assert_eq!(
162 JacobianConst::GENERATOR.double().double().to_affine(),
163 ecmult(
164 Jacobian::GENERATOR,
165 Scalar::from_words([2, 0, 0, 0]),
166 Scalar::from_words([2, 0, 0, 0]),
167 &TABLE_G
168 )
169 .to_affine()
170 );
171
172 assert_eq!(
173 JacobianConst::GENERATOR.double().double().to_affine(),
174 ecmult(
175 Jacobian::GENERATOR,
176 Scalar::from_words([3, 0, 0, 0]),
177 Scalar::ONE,
178 &TABLE_G
179 )
180 .to_affine()
181 );
182
183 assert_eq!(
184 JacobianConst::GENERATOR.double().double().to_affine(),
185 ecmult(
186 Jacobian::GENERATOR,
187 Scalar::ONE,
188 Scalar::from_words([3, 0, 0, 0]),
189 &TABLE_G
190 )
191 .to_affine()
192 );
193 }
194
195 #[test]
196 fn test_ecmult() {
197 for (k_bytes, x_bytes, y_bytes) in MUL_TEST_VECTORS {
198 let k = Scalar::reduce_be_bytes(k_bytes);
199 let expected = Jacobian {
200 x: FieldElement::from_be_bytes(x_bytes).unwrap(),
201 y: FieldElement::from_be_bytes(y_bytes).unwrap(),
202 z: FieldElement::ONE,
203 };
204
205 let result = ecmult(Jacobian::default(), Scalar::ZERO, k, &TABLE_G);
206 assert_eq!(result.to_affine(), expected.to_affine());
207
208 let result = ecmult(Jacobian::GENERATOR, k, Scalar::ZERO, &TABLE_G);
209 assert_eq!(result.to_affine(), expected.to_affine());
210 }
211 }
212}