1use crate::finite_fields::FiniteField;
103use num_bigint::BigUint;
104
105#[derive(PartialEq, Clone, Debug)]
114pub enum Point {
115 Coor(BigUint, BigUint),
116 Identity,
117}
118
119#[derive(PartialEq, Debug)]
120pub enum EllipticCurveError {
121 InvalidPoint(Point),
122 InvalidScalar(BigUint),
123}
124
125#[derive(PartialEq, Clone, Debug)]
130pub struct EllipticCurve {
131 pub a: BigUint,
132 pub b: BigUint,
133 pub p: BigUint,
134}
135
136impl EllipticCurve {
137 pub fn add(&self, a: &Point, b: &Point) -> Result<Point, EllipticCurveError> {
144 if !self.is_on_curve(a) {
145 return Err(EllipticCurveError::InvalidPoint(a.clone()));
146 }
147
148 if !self.is_on_curve(b) {
149 return Err(EllipticCurveError::InvalidPoint(b.clone()));
150 }
151
152 if *a == *b {
153 return self.double(a);
154 }
155
156 match (a, b) {
157 (Point::Identity, _) => Ok(b.clone()),
158 (_, Point::Identity) => Ok(a.clone()),
159 (Point::Coor(x1, y1), Point::Coor(x2, y2)) => {
160 let y1plusy2 = FiniteField::add(y1, y2, &self.p).unwrap();
162
163 if x1 == x2 && y1plusy2 == BigUint::from(0u32) {
164 return Ok(Point::Identity);
165 }
166
167 let numerator = FiniteField::subtract(y2, y1, &self.p).unwrap();
169 let denominator = FiniteField::subtract(x2, x1, &self.p).unwrap();
170
171 let s = FiniteField::divide(&numerator, &denominator, &self.p).unwrap();
172
173 let (x3, y3) = self.compute_x3_y3(x1, y1, x2, &s);
174
175 Ok(Point::Coor(x3, y3))
176 }
177 }
178 }
179
180 pub fn double(&self, a: &Point) -> Result<Point, EllipticCurveError> {
186 if !self.is_on_curve(a) {
187 return Err(EllipticCurveError::InvalidPoint(a.clone()));
188 }
189
190 match a {
191 Point::Identity => Ok(Point::Identity),
192 Point::Coor(x1, y1) => {
193 if *y1 == BigUint::from(0u32) {
194 return Ok(Point::Identity);
195 }
196
197 let numerator = x1.modpow(&BigUint::from(2u32), &self.p);
199 let numerator =
200 FiniteField::mult(&BigUint::from(3u32), &numerator, &self.p).unwrap();
201 let numerator = FiniteField::add(&self.a, &numerator, &self.p).unwrap();
202
203 let denominator = FiniteField::mult(&BigUint::from(2u32), y1, &self.p).unwrap();
204 let s = FiniteField::divide(&numerator, &denominator, &self.p).unwrap();
205
206 let (x3, y3) = self.compute_x3_y3(x1, y1, x1, &s);
207
208 Ok(Point::Coor(x3, y3))
209 }
210 }
211 }
212
213 fn compute_x3_y3(
229 &self,
230 x1: &BigUint,
231 y1: &BigUint,
232 x2: &BigUint,
233 s: &BigUint,
234 ) -> (BigUint, BigUint) {
235 let s2 = s.modpow(&BigUint::from(2u32), &self.p);
236 let x3 = FiniteField::subtract(&s2, x1, &self.p).unwrap();
237 let x3 = FiniteField::subtract(&x3, x2, &self.p).unwrap();
238
239 let y3 = FiniteField::subtract(x1, &x3, &self.p).unwrap();
240 let y3 = FiniteField::mult(s, &y3, &self.p).unwrap();
241 let y3 = FiniteField::subtract(&y3, y1, &self.p).unwrap();
242
243 (x3, y3)
244 }
245
246 pub fn scalar_mul(&self, a: &Point, d: &BigUint) -> Result<Point, EllipticCurveError> {
261 if *d == BigUint::from(0u32) {
262 return Err(EllipticCurveError::InvalidScalar(d.clone()));
263 }
264
265 let mut t = a.clone();
266 for i in (0..(d.bits() - 1)).rev() {
267 t = self.double(&t)?;
268 if d.bit(i) {
269 t = self.add(&t, a)?;
270 }
271 }
272 Ok(t)
273 }
274
275 pub fn is_on_curve(&self, a: &Point) -> bool {
282 match a {
283 Point::Coor(x, y) => {
284 let y2 = y.modpow(&BigUint::from(2u32), &self.p);
285 let x3 = x.modpow(&BigUint::from(3u32), &self.p);
286 let ax = FiniteField::mult(&self.a, x, &self.p).unwrap();
287 let x3plusax = FiniteField::add(&x3, &ax, &self.p).unwrap();
288
289 y2 == FiniteField::add(&x3plusax, &self.b, &self.p).unwrap()
290 }
291 Point::Identity => true,
292 }
293 }
294}
295
296#[cfg(test)]
297mod test {
298
299 use super::*;
300
301 #[test]
302 fn test_point_in_curve() {
303 let ec = EllipticCurve {
305 a: BigUint::from(2u32),
306 b: BigUint::from(2u32),
307 p: BigUint::from(17u32),
308 };
309
310 let p1 = Point::Coor(BigUint::from(6u32), BigUint::from(3u32));
312 let p2 = Point::Coor(BigUint::from(5u32), BigUint::from(1u32));
313 let p3 = Point::Coor(BigUint::from(10u32), BigUint::from(6u32));
314
315 assert!(ec.is_on_curve(&p1));
316 assert!(ec.is_on_curve(&p2));
317 assert!(ec.is_on_curve(&p3));
318
319 let p4 = Point::Coor(BigUint::from(4u32), BigUint::from(1u32));
320 let p5 = Point::Coor(BigUint::from(1u32), BigUint::from(1u32));
321 let p6 = Point::Coor(BigUint::from(0u32), BigUint::from(1u32));
322
323 assert!(!ec.is_on_curve(&p4));
324 assert!(!ec.is_on_curve(&p5));
325 assert!(!ec.is_on_curve(&p6));
326 }
327
328 #[test]
329 fn test_point_addition() {
330 let ec = EllipticCurve {
332 a: BigUint::from(2u32),
333 b: BigUint::from(2u32),
334 p: BigUint::from(17u32),
335 };
336
337 let p1 = Point::Coor(BigUint::from(6u32), BigUint::from(3u32));
339 let p2 = Point::Coor(BigUint::from(5u32), BigUint::from(1u32));
340 let pr = Ok(Point::Coor(BigUint::from(10u32), BigUint::from(6u32)));
341
342 let res = ec.add(&p1, &p2);
343 assert_eq!(res, pr);
344
345 let res = ec.add(&p2, &p1);
346 assert_eq!(res, pr);
347
348 let p1 = Point::Coor(BigUint::from(5u32), BigUint::from(1u32));
350 let p2 = Point::Coor(BigUint::from(5u32), BigUint::from(1u32));
351 let pr = Ok(Point::Coor(BigUint::from(6u32), BigUint::from(3u32)));
352
353 let res = ec.add(&p1, &p2);
354 assert_eq!(res, pr);
355
356 let p1 = Point::Coor(BigUint::from(10u32), BigUint::from(6u32));
358 let p2 = Point::Coor(BigUint::from(5u32), BigUint::from(1u32));
359 let pr = Ok(Point::Coor(BigUint::from(3u32), BigUint::from(1u32)));
360
361 let res = ec.add(&p1, &p2);
362 assert_eq!(res, pr);
363
364 let p1 = Point::Coor(BigUint::from(16u32), BigUint::from(13u32));
366 let p2 = Point::Coor(BigUint::from(5u32), BigUint::from(1u32));
367 let pr = Ok(Point::Coor(BigUint::from(0u32), BigUint::from(6u32)));
368
369 let res = ec.add(&p1, &p2);
370 assert_eq!(res, pr);
371
372 let p1 = Point::Coor(BigUint::from(6u32), BigUint::from(3u32));
374
375 let res = ec.add(&p1, &Point::Identity);
376 assert_eq!(res, Ok(p1.clone()));
377
378 let res = ec.add(&Point::Identity, &p1);
379 assert_eq!(res, Ok(p1.clone()));
380
381 let res = ec.add(&Point::Identity, &Point::Identity);
383 assert_eq!(res, Ok(Point::Identity));
384
385 let p1 = Point::Coor(BigUint::from(5u32), BigUint::from(16u32));
387 let p2 = Point::Coor(BigUint::from(5u32), BigUint::from(1u32));
388
389 let res = ec.add(&p1, &p2);
390 assert_eq!(res, Ok(Point::Identity));
391
392 let res = ec.add(&p2, &p1);
393 assert_eq!(res, Ok(Point::Identity));
394 }
395
396 #[test]
397 fn test_point_doubling() {
398 let ec = EllipticCurve {
400 a: BigUint::from(2u32),
401 b: BigUint::from(2u32),
402 p: BigUint::from(17u32),
403 };
404
405 let p1 = Point::Coor(BigUint::from(5u32), BigUint::from(1u32));
407 let pr = Ok(Point::Coor(BigUint::from(6u32), BigUint::from(3u32)));
408
409 let res = ec.double(&p1);
410 assert_eq!(res, pr);
411
412 let res = ec.double(&Point::Identity);
414 assert_eq!(res, Ok(Point::Identity));
415 }
416
417 #[test]
418 fn test_scalar_multiplication() {
419 let ec = EllipticCurve {
421 a: BigUint::from(2u32),
422 b: BigUint::from(2u32),
423 p: BigUint::from(17u32),
424 };
425
426 let a = Point::Coor(BigUint::from(5u32), BigUint::from(1u32));
427
428 let pr = Ok(Point::Coor(BigUint::from(6u32), BigUint::from(3u32)));
430 let res = ec.scalar_mul(&a, &BigUint::from(2u32));
431 assert_eq!(res, pr);
432
433 let pr = Ok(Point::Coor(BigUint::from(7u32), BigUint::from(11u32)));
435 let res = ec.scalar_mul(&a, &BigUint::from(10u32));
436 assert_eq!(res, pr);
437
438 let pr = Ok(Point::Coor(BigUint::from(3u32), BigUint::from(16u32)));
440 let res = ec.scalar_mul(&a, &BigUint::from(15u32));
441 assert_eq!(res, pr);
442
443 let pr = Ok(Point::Coor(BigUint::from(10u32), BigUint::from(11u32)));
445 let res = ec.scalar_mul(&a, &BigUint::from(16u32));
446 assert_eq!(res, pr);
447
448 let pr = Ok(Point::Coor(BigUint::from(6u32), BigUint::from(14u32)));
450 let res = ec.scalar_mul(&a, &BigUint::from(17u32));
451 assert_eq!(res, pr);
452
453 let pr = Ok(Point::Coor(BigUint::from(5u32), BigUint::from(16u32)));
455 let res = ec.scalar_mul(&a, &BigUint::from(18u32));
456 assert_eq!(res, pr);
457
458 let pr = Ok(Point::Identity);
460 let res = ec.scalar_mul(&a, &BigUint::from(19u32));
461 assert_eq!(res, pr);
462
463 let p1 = Point::Coor(BigUint::from(10u32), BigUint::from(6u32));
465 let pr = Ok(Point::Coor(BigUint::from(16u32), BigUint::from(13u32)));
466
467 let res = ec.double(&p1);
468 assert_eq!(res, pr);
469 }
470
471 #[test]
472 fn test_ec_secp256k1() {
473 let p = BigUint::parse_bytes(
488 b"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F",
489 16,
490 )
491 .expect("could not convert p");
492
493 let n = BigUint::parse_bytes(
494 b"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",
495 16,
496 )
497 .expect("could not convert n");
498
499 let gx = BigUint::parse_bytes(
500 b"79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
501 16,
502 )
503 .expect("could not convert gx");
504
505 let gy = BigUint::parse_bytes(
506 b"483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8",
507 16,
508 )
509 .expect("could not convert gy");
510
511 let ec = EllipticCurve {
512 a: BigUint::from(0u32),
513 b: BigUint::from(7u32),
514 p,
515 };
516
517 let g = Point::Coor(gx, gy);
518
519 let res = ec.scalar_mul(&g, &n); assert_eq!(res, Ok(Point::Identity));
521
522 let p = ec.scalar_mul(&g, &BigUint::from(1201u32)).unwrap();
524
525 let res = ec.scalar_mul(&p, &n); assert_eq!(res, Ok(Point::Identity));
527 }
528}