1use hacspec_lib::{hacspec_helper::*, i2osp, Randomness};
2use hmac::{hkdf_expand, hkdf_extract};
3
4#[derive(Debug)]
5pub enum Error {
6 InvalidAddition,
7 DeserializeError,
8 PointAtInfinity,
9 SamplingError,
10}
11
12impl From<hacspec_lib::Error> for Error {
13 fn from(_value: hacspec_lib::Error) -> Self {
14 Self::SamplingError
15 }
16}
17
18const BITS: u128 = 256;
19
20#[derive(Hash, PartialOrd, Ord)]
21#[nat_mod("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", 32)]
22pub struct P256FieldElement {}
23
24#[nat_mod("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 32)]
25pub struct P256Scalar {}
26
27pub fn random_scalar(randomness: &mut Randomness, dst: &[u8]) -> Result<P256Scalar, Error> {
42 let dkp_prk = hkdf_extract(dst, randomness.bytes(32).unwrap());
43
44 let mut sk = P256Scalar::zero();
45
46 for counter in 0..255 {
47 let mut bytes = hkdf_expand(&dkp_prk, &i2osp(counter, 1), 32);
48
49 bytes[0] &= 0xffu8;
50 if p256_validate_private_key(&bytes) {
51 sk = P256Scalar::from_be_bytes(&bytes);
52 }
53 }
54 if sk == P256Scalar::zero() {
55 Err(Error::SamplingError)
56 } else {
57 Ok(sk)
58 }
59}
60
61pub type Affine = (P256FieldElement, P256FieldElement);
62pub type AffineResult = Result<Affine, Error>;
63type P256Jacobian = (P256FieldElement, P256FieldElement, P256FieldElement);
64type JacobianResult = Result<P256Jacobian, Error>;
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
67pub enum P256Point {
68 NonInf(Affine),
69 AtInfinity,
70}
71
72impl From<P256Point> for Affine {
73 fn from(value: P256Point) -> Self {
74 match value {
75 P256Point::AtInfinity => panic!("No affine representation of Point at Infinity."),
76 P256Point::NonInf(affine) => affine,
77 }
78 }
79}
80
81impl From<Affine> for P256Point {
82 fn from(value: Affine) -> Self {
83 P256Point::NonInf(value)
84 }
85}
86
87pub fn jacobian_to_affine(p: P256Jacobian) -> Affine {
88 let (x, y, z) = p;
89 let z2 = z.pow(2);
90 let z2i = z2.inv();
91 let z3 = z * z2;
92 let z3i = z3.inv();
93 let x = x * z2i;
94 let y = y * z3i;
95 (x, y)
96}
97
98impl std::ops::Neg for P256FieldElement {
99 type Output = P256FieldElement;
100
101 fn neg(self) -> Self::Output {
102 NatMod::neg(self)
103 }
104}
105
106pub fn is_square(x: &P256FieldElement) -> bool {
107 let exp = P256FieldElement::from_u128(1).neg() * P256FieldElement::from_u128(2).inv();
108 let test = x.pow_felem(&exp);
109 test == P256FieldElement::zero() || test == P256FieldElement::one()
110}
111
112pub fn sgn0(x: &P256FieldElement) -> bool {
113 x.bit(0)
114}
115
116pub fn sqrt(x: &P256FieldElement) -> P256FieldElement {
117 let c1 = P256FieldElement::one() * P256FieldElement::from_u128(4).inv();
118 x.pow_felem(&c1)
119}
120
121impl std::ops::Neg for P256Point {
122 type Output = P256Point;
123 fn neg(self) -> Self::Output {
124 match self {
125 P256Point::AtInfinity => self,
126 P256Point::NonInf((x, y)) => (x, NatMod::neg(y)).into(),
127 }
128 }
129}
130
131fn affine_to_jacobian(p: Affine) -> P256Jacobian {
132 let (x, y) = p;
133 (x, y, P256FieldElement::from_u128(1))
134}
135
136fn point_double(p: P256Jacobian) -> P256Jacobian {
137 let (x1, y1, z1) = p;
138 let delta = z1.pow(2);
139 let gamma = y1.pow(2);
140
141 let beta = x1 * gamma;
142
143 let alpha_1 = x1 - delta;
144 let alpha_2 = x1 + delta;
145 let alpha = P256FieldElement::from_u128(3) * (alpha_1 * alpha_2);
146
147 let x3 = alpha.pow(2) - (P256FieldElement::from_u128(8) * beta);
148
149 let z3_ = (y1 + z1).pow(2);
150 let z3 = z3_ - (gamma + delta);
151
152 let y3_1 = (P256FieldElement::from_u128(4) * beta) - x3;
153 let y3_2 = P256FieldElement::from_u128(8) * (gamma * gamma);
154 let y3 = (alpha * y3_1) - y3_2;
155 (x3, y3, z3)
156}
157
158fn is_point_at_infinity(p: P256Jacobian) -> bool {
159 let (_x, _y, z) = p;
160 z == P256FieldElement::from_u128(0)
161}
162
163fn s1_equal_s2(s1: P256FieldElement, s2: P256FieldElement) -> JacobianResult {
164 if s1 == s2 {
165 JacobianResult::Err(Error::InvalidAddition)
166 } else {
167 Ok((
168 P256FieldElement::from_u128(0),
169 P256FieldElement::from_u128(1),
170 P256FieldElement::from_u128(0),
171 ))
172 }
173}
174
175fn point_add_jacob(p: P256Jacobian, q: P256Jacobian) -> JacobianResult {
176 let mut result = Ok(q);
177 if !is_point_at_infinity(p) {
178 if is_point_at_infinity(q) {
179 result = Ok(p);
180 } else {
181 let (x1, y1, z1) = p;
182 let (x2, y2, z2) = q;
183 let z1z1 = z1.pow(2);
184 let z2z2 = z2.pow(2);
185 let u1 = x1 * z2z2;
186 let u2 = x2 * z1z1;
187 let s1 = (y1 * z2) * z2z2;
188 let s2 = (y2 * z1) * z1z1;
189
190 if u1 == u2 {
191 result = s1_equal_s2(s1, s2);
192 } else {
193 let h = u2 - u1;
194 let i = (P256FieldElement::from_u128(2) * h).pow(2);
195 let j = h * i;
196 let r = P256FieldElement::from_u128(2) * (s2 - s1);
197 let v = u1 * i;
198
199 let x3_1 = P256FieldElement::from_u128(2) * v;
200 let x3_2 = r.pow(2) - j;
201 let x3 = x3_2 - x3_1;
202
203 let y3_1 = (P256FieldElement::from_u128(2) * s1) * j;
204 let y3_2 = r * (v - x3);
205 let y3 = y3_2 - y3_1;
206
207 let z3_ = (z1 + z2).pow(2);
208 let z3 = (z3_ - (z1z1 + z2z2)) * h;
209 result = Ok((x3, y3, z3));
210 }
211 }
212 };
213 result
214}
215
216fn ltr_mul(k: P256Scalar, p: P256Jacobian) -> JacobianResult {
217 let mut q = (
218 P256FieldElement::from_u128(0),
219 P256FieldElement::from_u128(1),
220 P256FieldElement::from_u128(0),
221 );
222 for i in 0..BITS {
223 q = point_double(q);
224 if k.bit(BITS - 1 - i) {
225 q = point_add_jacob(q, p)?;
226 }
227 }
228 Ok(q)
229}
230
231pub type P256SerializedPoint = [u8; 33];
232
233pub fn serialize_point(p: &P256Point) -> P256SerializedPoint {
238 let mut out = [0u8; 33];
239 match p {
240 P256Point::AtInfinity => out,
241 P256Point::NonInf((x, y)) => {
242 let x_serialized = x.to_be_bytes();
243
244 for (to, from) in out.iter_mut().skip(1).zip(x_serialized.iter()) {
245 *to = *from
246 }
247 out[0] = if y.bit(0) { 3 } else { 2 };
248
249 out
250 }
251 }
252}
253impl P256Point {
254 pub fn raw_bytes(&self) -> [u8; 64] {
255 match self {
256 P256Point::NonInf((x, y)) => {
257 let mut out = [0u8; 64];
258 out[0..32].copy_from_slice(&x.to_be_bytes());
259 out[32..64].copy_from_slice(&y.to_be_bytes());
260 out
261 }
262 P256Point::AtInfinity => panic!("Tried to serialize point at infitiy"),
263 }
264 }
265
266 pub fn from_raw_bytes(bytes: [u8; 64]) -> Result<P256Point, Error> {
267 let x = P256FieldElement::from_be_bytes(&bytes[0..32]);
268 let y = P256FieldElement::from_be_bytes(&bytes[32..64]);
269 let candidate = P256Point::NonInf((x, y));
270 if p256_validate_public_key(candidate) {
271 Ok(candidate)
272 } else {
273 Err(Error::DeserializeError)
274 }
275 }
276
277 pub fn x(&self) -> Result<P256FieldElement, Error> {
278 match self {
279 P256Point::NonInf((x, _)) => Ok(*x),
280 P256Point::AtInfinity => Err(Error::PointAtInfinity),
281 }
282 }
283 pub fn y(&self) -> Result<P256FieldElement, Error> {
284 match self {
285 P256Point::NonInf((_, y)) => Ok(*y),
286 P256Point::AtInfinity => Err(Error::PointAtInfinity),
287 }
288 }
289}
290
291#[allow(unused)]
292pub fn deserialize_point(pm: P256SerializedPoint) -> Result<P256Point, Error> {
293 if pm == [0u8; 33] {
294 return Err(Error::DeserializeError);
295 }
296
297 let x = P256FieldElement::from_be_bytes(&pm[1..33]);
298
299 let ym = pm[0];
300 let yp_sign: bool = match ym {
301 0x02 => false,
302 0x03 => true,
303 _ => return Err(Error::DeserializeError),
304 };
305
306 let a = P256FieldElement::from_u128(3u128).neg();
307 let b = P256FieldElement::from_hex(
308 "5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
309 );
310
311 let alpha = x.pow(3) + a * x + b;
312 let beta = sqrt(&alpha);
313
314 let y: P256FieldElement = if beta.bit(0) == yp_sign {
315 beta
316 } else {
317 beta.neg()
318 };
319
320 Ok((x, y).into())
321}
322
323pub fn p256_point_mul(k: P256Scalar, p: P256Point) -> Result<P256Point, Error> {
324 let jac = ltr_mul(k, affine_to_jacobian(p.into()))?;
325 Ok(jacobian_to_affine(jac).into())
326}
327
328pub fn p256_point_mul_base(k: P256Scalar) -> Result<P256Point, Error> {
329 let base_point = (
330 P256FieldElement::from_be_bytes(&[
331 0x6Bu8, 0x17u8, 0xD1u8, 0xF2u8, 0xE1u8, 0x2Cu8, 0x42u8, 0x47u8, 0xF8u8, 0xBCu8, 0xE6u8,
332 0xE5u8, 0x63u8, 0xA4u8, 0x40u8, 0xF2u8, 0x77u8, 0x03u8, 0x7Du8, 0x81u8, 0x2Du8, 0xEBu8,
333 0x33u8, 0xA0u8, 0xF4u8, 0xA1u8, 0x39u8, 0x45u8, 0xD8u8, 0x98u8, 0xC2u8, 0x96u8,
334 ]),
335 P256FieldElement::from_be_bytes(&[
336 0x4Fu8, 0xE3u8, 0x42u8, 0xE2u8, 0xFEu8, 0x1Au8, 0x7Fu8, 0x9Bu8, 0x8Eu8, 0xE7u8, 0xEBu8,
337 0x4Au8, 0x7Cu8, 0x0Fu8, 0x9Eu8, 0x16u8, 0x2Bu8, 0xCEu8, 0x33u8, 0x57u8, 0x6Bu8, 0x31u8,
338 0x5Eu8, 0xCEu8, 0xCBu8, 0xB6u8, 0x40u8, 0x68u8, 0x37u8, 0xBFu8, 0x51u8, 0xF5u8,
339 ]),
340 )
341 .into();
342 p256_point_mul(k, base_point)
343}
344
345fn point_add_distinct(p: Affine, q: Affine) -> AffineResult {
346 let r = point_add_jacob(affine_to_jacobian(p), affine_to_jacobian(q))?;
347 Ok(jacobian_to_affine(r))
348}
349
350pub fn point_add(p: P256Point, q: P256Point) -> Result<P256Point, Error> {
351 match p {
352 P256Point::AtInfinity => Ok(q),
353 P256Point::NonInf(p) => match q {
354 P256Point::AtInfinity => Ok(P256Point::AtInfinity),
355 P256Point::NonInf(q) => point_add_noninf(p, q).map(P256Point::NonInf),
356 },
357 }
358}
359
360fn point_add_noninf(p: Affine, q: Affine) -> AffineResult {
361 if p != q {
362 point_add_distinct(p, q)
363 } else {
364 Ok(jacobian_to_affine(point_double(affine_to_jacobian(p))))
365 }
366}
367
368pub fn p256_validate_private_key(k: &[u8]) -> bool {
370 let mut valid = true;
371 let k_element = P256Scalar::from_be_bytes(k);
373 let k_element_bytes = k_element.to_be_bytes();
374 let mut all_zero = true;
375 for i in 0..k.len() {
376 if !k[i] == U8(0u8) {
377 all_zero = false;
378 }
379 if !k_element_bytes[i] == k[i] {
380 valid = false;
381 }
382 }
383 valid && !all_zero
384}
385
386pub fn p256_validate_public_key(p: P256Point) -> bool {
388 let b = P256FieldElement::from_be_bytes(&[
389 0x5au8, 0xc6u8, 0x35u8, 0xd8u8, 0xaau8, 0x3au8, 0x93u8, 0xe7u8, 0xb3u8, 0xebu8, 0xbdu8,
390 0x55u8, 0x76u8, 0x98u8, 0x86u8, 0xbcu8, 0x65u8, 0x1du8, 0x06u8, 0xb0u8, 0xccu8, 0x53u8,
391 0xb0u8, 0xf6u8, 0x3bu8, 0xceu8, 0x3cu8, 0x3eu8, 0x27u8, 0xd2u8, 0x60u8, 0x4bu8,
392 ]);
393 let point_at_infinity = is_point_at_infinity(affine_to_jacobian(p.into()));
394 let (x, y) = p.into();
395 let on_curve = y * y == x * x * x - P256FieldElement::from_u128(3) * x + b;
396
397 !point_at_infinity && on_curve
398}
399
400pub fn p256_calculate_w(x: P256FieldElement) -> P256FieldElement {
402 let b = P256FieldElement::from_be_bytes(&[
403 0x5au8, 0xc6u8, 0x35u8, 0xd8u8, 0xaau8, 0x3au8, 0x93u8, 0xe7u8, 0xb3u8, 0xebu8, 0xbdu8,
404 0x55u8, 0x76u8, 0x98u8, 0x86u8, 0xbcu8, 0x65u8, 0x1du8, 0x06u8, 0xb0u8, 0xccu8, 0x53u8,
405 0xb0u8, 0xf6u8, 0x3bu8, 0xceu8, 0x3cu8, 0x3eu8, 0x27u8, 0xd2u8, 0x60u8, 0x4bu8,
406 ]);
407 let pow = P256FieldElement::from_be_bytes(&[
409 0x3fu8, 0xffu8, 0xffu8, 0xffu8, 0xc0u8, 0x00u8, 0x00u8, 0x00u8, 0x40u8, 0x00u8, 0x00u8,
410 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x40u8, 0x00u8,
411 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8,
412 ]);
413 let z = x * x * x - P256FieldElement::from_u128(3) * x + b;
415 z.pow_felem(&pow)
417}