Skip to content

Commit f713bfc

Browse files
committed
feat: implement ECurve, EPoint
1 parent e419dac commit f713bfc

File tree

2 files changed

+160
-0
lines changed

2 files changed

+160
-0
lines changed

src/ec.rs

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
#![allow(dead_code)]
2+
3+
use std::ops;
4+
5+
// An elliptic curve defined by the equation y**2 = x**3 + Ax + B
6+
#[derive(Debug, Eq, PartialEq)]
7+
pub struct ECurve<const A: i32, const B: i32>;
8+
9+
// Coordinates of a point on the curve
10+
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
11+
pub struct Coordinates {
12+
pub x: i32,
13+
pub y: i32,
14+
}
15+
16+
// A point contained in the elliptic curve defined by A and B
17+
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
18+
pub struct EPoint<const A: i32, const B: i32> {
19+
// None represents the point at infinity
20+
p: Option<Coordinates>,
21+
}
22+
23+
impl<const A: i32, const B: i32> EPoint<A, B> {
24+
// Constructor for the point at infinity
25+
pub const fn infinity() -> Self {
26+
Self { p: None }
27+
}
28+
29+
// Constructor for a regular point
30+
pub const fn new(x: i32, y: i32) -> Self {
31+
Self {
32+
p: Some(Coordinates { x, y }),
33+
}
34+
}
35+
36+
// Check if this is the point at infinity
37+
pub const fn is_infinity(&self) -> bool {
38+
self.p.is_none()
39+
}
40+
41+
// Get the coordinates, or None for point at infinity
42+
pub const fn coords(&self) -> Option<Coordinates> {
43+
self.p
44+
}
45+
}
46+
47+
impl<const A: i32, const B: i32> ECurve<A, B> {
48+
pub const fn new() -> Self {
49+
ECurve
50+
}
51+
52+
pub const fn point_at(&self, x: i32, y: i32) -> Option<EPoint<A, B>> {
53+
if self.contains(x, y) {
54+
Some(EPoint {
55+
p: Some(Coordinates { x, y }),
56+
})
57+
} else {
58+
None
59+
}
60+
}
61+
62+
pub const fn point_at_ifty(&self) -> EPoint<A, B> {
63+
EPoint::<A, B>::infinity()
64+
}
65+
66+
pub const fn a(&self) -> i32 {
67+
A
68+
}
69+
70+
pub const fn b(&self) -> i32 {
71+
B
72+
}
73+
74+
pub const fn contains(&self, x: i32, y: i32) -> bool {
75+
y * y == x * x * x + A * x + B
76+
}
77+
}
78+
79+
impl<const A: i32, const B: i32> ops::Add for EPoint<A, B> {
80+
type Output = Self;
81+
82+
fn add(self, other: Self) -> Self {
83+
// ECurve addition is performed by intersecting a line between the two
84+
// points to add. There are three main cases: the intersects the curve
85+
// at either one, two or three points.
86+
// For two intersections, the line is either vertical (one point is at infinity) or tangent to the curve.
87+
88+
// Handle common cases first:
89+
// 1. Either point is an infinity. This point is the identity point, i.e., A + Ifty = A
90+
91+
if self.is_infinity() {
92+
return other;
93+
} else if other.is_infinity() {
94+
return self;
95+
}
96+
97+
// At this point (lol) we know that neither point is at infinity.
98+
let self_coords = self.coords().unwrap();
99+
let other_coords = other.coords().unwrap();
100+
101+
// 2. Points are additive inverses. The two points have the same x coord but different y.
102+
if self_coords.x == other_coords.x && self_coords.y != other_coords.y {
103+
return EPoint::<A, B>::infinity();
104+
}
105+
106+
unimplemented!()
107+
}
108+
}
109+
110+
pub const SECP256K1: ECurve<0, 7> = ECurve::new();
111+
112+
#[cfg(test)]
113+
mod tests {
114+
use super::*;
115+
116+
// This is the example elliptic curve used in the book.
117+
const TEST_EC: ECurve<5, 7> = ECurve::<5, 7>::new();
118+
119+
#[test]
120+
fn test_ec_new() {
121+
_ = ECurve::<0, 7>::new();
122+
}
123+
124+
#[test]
125+
fn test_contains() {
126+
let contained = TEST_EC.contains(-1, 1);
127+
let not_contained = TEST_EC.contains(-1, -2);
128+
129+
assert!(contained);
130+
assert!(!not_contained);
131+
}
132+
133+
#[test]
134+
fn test_point_at() {
135+
let exists = TEST_EC.point_at(-1, 1);
136+
let not_exists = TEST_EC.point_at(-1, -2);
137+
138+
assert!(exists.is_some());
139+
assert!(not_exists.is_none());
140+
}
141+
142+
#[test]
143+
fn test_add_ifty() {
144+
let a = TEST_EC.point_at(-1, 1).unwrap();
145+
let ifty = TEST_EC.point_at_ifty();
146+
147+
assert_eq!(a + ifty, a);
148+
assert_eq!(ifty + a, a);
149+
}
150+
151+
#[test]
152+
fn test_add_ident() {
153+
let a = TEST_EC.point_at(-1, 1).unwrap();
154+
let b = TEST_EC.point_at(-1, -1).unwrap();
155+
156+
assert_eq!(a + b, TEST_EC.point_at_ifty());
157+
assert_eq!(b + a, TEST_EC.point_at_ifty());
158+
}
159+
}

src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod ec;
12
mod finite_field;
23

34
fn main() {

0 commit comments

Comments
 (0)