Skip to content

Commit a859cbe

Browse files
authored
feat: Tate pairing (#67)
* feat: basic setup * add: `README` in curve module * impl Tonelli-Shanks sqrt * feat: 17-torsion generators * bug: `curve::tests::fields::double_distorted_generator()` fails * fix: `GaloisField<2, 59>::inverse()` * feat: vertical line functions * fix: lhs scalar mul * feat: tangent line * test: `line_from_p_to_2p` * fix: `point_doubling()` * bug: `miller_loop_check()` does not pass yet * fix: `panic!`s on `AffinePoint::Infinity` * wip * feat: miller loop test passes * update generator * cleanup pairing * clean lint * fix: incorrect field names
1 parent d580c83 commit a859cbe

12 files changed

Lines changed: 809 additions & 75 deletions

File tree

math/field.sage

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ print(F)
77
primitive_element = F.primitive_element()
88
print("The primitive element is: ", primitive_element)
99

10+
# Quadratic Residues
11+
elements = [F(i) for i in range(1,101)]
12+
quadratic_residues = [x^2 for x in elements]
13+
print("The quadratic residues are: ", sorted(set(quadratic_residues)))
14+
1015
######################################################################
1116
# Let's find a mth root of unity (for m = 5)
1217
# First, check that m divides 101 - 1 = 100
@@ -102,4 +107,4 @@ denominator = F_2(62*t)
102107

103108
# Compute the division of 50 by 60t in the extension field
104109
result = numerator / denominator
105-
print("The division of 50 by 60t in the extension field is:", result)
110+
print("The division of 50 by 60t in the extension field is:", result)

src/curve/README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Curves
2+
Everything in `ronkathon` (and much of modern day cryptography) works with elliptic curves $E$ as primitives.
3+
Simply put, an elliptic curve is a curve defined by the equation $y^2 = x^3 + ax + b$ where $a$ and $b$ are constants that define the curve.
4+
When working over a finite field so that $x, y a, b \in \mathbb{F}_q$, we put $E(\mathbb{F}_q)$ to denote the set of points on the curve over the field $\mathbb{F}_q$.
5+
It turns out that the set of points $E(\mathbb{F}_q)$ forms a group under a certain operation called point addition.
6+
This group, in at least certain cases, is discrete logarithm hard, which is the basis for much of modern day cryptography.
7+
8+
## Pluto Curve
9+
For the sake of `ronkathon`, we use a specific curve which we affectionately call the "Pluto Curve."
10+
Our equation is:
11+
$$y^2 = x^3 + 3$$
12+
and we work with the field $\mathbb{F}_{p}$ and $\mathbb{F}_{p^2}$ where $p = 101$.
13+
Predominantly, we use the extension $\mathbb{F}_{p^2}$ since we need this for the [Tate pairing](https://en.wikipedia.org/wiki/Tate_pairing) operation.
14+
We refer to $\mathbb{F}_{101}$ as the `PlutoBaseField` and $\mathbb{F}_{101^2}$ as the `PlutoBaseFieldExtension` within `ronkathon`.
15+
From which, we also use the terminology of `PlutoCurve` to refer to $E(\mathbb{F}_{101})$ and `PlutoExtendedCurve` to refer to $E(\mathbb{F}_{101^2})$.
16+
17+
### Type B
18+
Investigating our curve and choice of field, we find that the curve is Type B since:
19+
- It is of the form $y^2 = x^3 + b$;
20+
- $p = 101 \equiv 2 \mod 3$;
21+
It follows that $E(\mathbb{F}_{101})$ is [supersingular](https://en.wikipedia.org/wiki/Supersingular_elliptic_curve) which implies that the `PlutoCurve` has order (number of points) $n = 101 + 1 = 102$ and `PlutoExtendedCurve` has order $n^2 = 102^2 = 10404$.
22+
Finally, the embedding degree of the curve is $k=2$.
23+
24+
This allows us to define the Tate pairing $e \colon G \times G \to \mathbb{F}_{p^2}$ in a convenient manner.
25+
In particular, we can pick $G$ to be the [$r$-torsion subgroup](https://crypto.stanford.edu/pbc/notes/elliptic/torsion.html) of `PlutoCurve` where $r = 17$ is the [scalar field](https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication) of the curve.
26+
Note that $r=17$ is valid since $17 \nmid 101-1$ and $17 \mid 101^2 -1$ ([Balasubramanian-Koblitz theorem](https://crypto.stanford.edu/pbc/notes/ep/bk.html)).
27+
28+
In this case, we pick $G = \mathbb{Z}_{17}$ and define our pairing as:
29+
$$e(P, Q) = f(P, \Psi(Q))^{(p^2-1)/r}$$
30+
where $f$ is the Tate pairing and $\Psi$ is the map $\Psi(x,y) = (\zeta x, y)$ where $\zeta$ is a primitive cube root of unity.
31+
This is due to the fact that $\Psi$ maps a factor of $E(\mathbb{F}_{101^2})[17] \cong \mathbb{Z}_{17} \times \mathbb{Z}_{17}$ (which is the $17$-torsion group) to the other.

src/curve/mod.rs

Lines changed: 59 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
33
use super::*;
44

5+
pub mod pairing;
56
pub mod pluto_curve;
7+
#[cfg(test)] mod tests;
68

79
/// Elliptic curve parameters for a curve over a finite field in Weierstrass form
810
/// `y^2 = x^3 + ax + b`
@@ -14,18 +16,15 @@ pub trait EllipticCurve: Copy {
1416
type BaseField: FiniteField;
1517

1618
/// Order of this elliptic curve, i.e. number of elements in the scalar field.
17-
type ScalarField: FiniteField;
18-
19-
/// Order of this elliptic curve, i.e. number of elements in the scalar field.
20-
const ORDER: usize = Self::ScalarField::ORDER;
19+
const ORDER: usize;
2120

2221
/// Coefficient `a` in the Weierstrass equation of this elliptic curve.
2322
const EQUATION_A: Self::Coefficient;
2423

2524
/// Coefficient `b` in the Weierstrass equation of this elliptic curve.
2625
const EQUATION_B: Self::Coefficient;
2726

28-
/// Generator of this elliptic curve.
27+
/// Generator of the scalar field to the elliptic curve.
2928
const GENERATOR: (Self::BaseField, Self::BaseField);
3029
}
3130

@@ -35,7 +34,7 @@ pub trait EllipticCurve: Copy {
3534
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
3635
pub enum AffinePoint<C: EllipticCurve> {
3736
/// A point on the curve.
38-
PointOnCurve(C::BaseField, C::BaseField),
37+
Point(C::BaseField, C::BaseField),
3938

4039
/// The point at infinity.
4140
Infinity,
@@ -49,20 +48,58 @@ impl<C: EllipticCurve> AffinePoint<C> {
4948
x * x * x + C::EQUATION_A.into() * x + C::EQUATION_B.into(),
5049
"Point is not on curve"
5150
);
52-
Self::PointOnCurve(x, y)
51+
Self::Point(x, y)
5352
}
5453
}
5554

56-
// Example:
57-
// Base
55+
impl<C: EllipticCurve> Add for AffinePoint<C> {
56+
type Output = AffinePoint<C>;
57+
58+
fn add(self, rhs: Self) -> Self::Output {
59+
// infty checks
60+
match (self, rhs) {
61+
(AffinePoint::Infinity, _) => return rhs,
62+
(_, AffinePoint::Infinity) => return self,
63+
64+
_ => (),
65+
}
66+
let (x1, y1) = match self {
67+
AffinePoint::Point(x, y) => (x, y),
68+
AffinePoint::Infinity => unreachable!(),
69+
};
70+
let (x2, y2) = match rhs {
71+
AffinePoint::Point(x, y) => (x, y),
72+
AffinePoint::Infinity => unreachable!(),
73+
};
74+
if x1 == x2 && y1 == -y2 {
75+
return AffinePoint::Infinity;
76+
}
77+
// compute new point using elliptic curve point group law
78+
// https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication
79+
let lambda = if x1 == x2 && y1 == y2 {
80+
((C::BaseField::ONE + C::BaseField::ONE + C::BaseField::ONE) * x1 * x1 + C::EQUATION_A.into())
81+
/ ((C::BaseField::ONE + C::BaseField::ONE) * y1)
82+
} else {
83+
(y2 - y1) / (x2 - x1)
84+
};
85+
let x = lambda * lambda - x1 - x2;
86+
let y = lambda * (x1 - x) - y1;
87+
88+
AffinePoint::new(x, y)
89+
}
90+
}
91+
92+
impl<C: EllipticCurve> AddAssign for AffinePoint<C> {
93+
fn add_assign(&mut self, rhs: Self) { *self = *self + rhs; }
94+
}
5895

5996
impl<C: EllipticCurve> Neg for AffinePoint<C> {
6097
type Output = AffinePoint<C>;
6198

6299
fn neg(self) -> Self::Output {
63100
let (x, y) = match self {
64-
AffinePoint::PointOnCurve(x, y) => (x, -y),
65-
AffinePoint::Infinity => panic!("Cannot double point at infinity"),
101+
AffinePoint::Point(x, y) => (x, -y),
102+
AffinePoint::Infinity => return AffinePoint::Infinity,
66103
};
67104
AffinePoint::new(x, y)
68105
}
@@ -79,65 +116,23 @@ impl<C: EllipticCurve> Mul<u32> for AffinePoint<C> {
79116
fn mul(mut self, scalar: u32) -> Self::Output {
80117
let val = self;
81118
for _ in 1..scalar {
82-
self = self + val;
119+
self += val;
83120
}
84121
self
85122
}
86123
}
87124

88125
/// Scalar multiplication on the Lhs (u32)*P
126+
#[allow(clippy::suspicious_arithmetic_impl)]
89127
impl<C: EllipticCurve> std::ops::Mul<AffinePoint<C>> for u32 {
90128
type Output = AffinePoint<C>;
91129

92-
fn mul(self, _rhs: AffinePoint<C>) -> Self::Output {
93-
let mut result = AffinePoint::Infinity;
94-
let mut base = AffinePoint::generator();
95-
let mut exp = self;
96-
97-
while exp > 0 {
98-
if exp % 2 == 1 {
99-
result = result + base;
100-
}
101-
base = base.point_doubling();
102-
exp /= 2;
103-
}
104-
result
105-
}
106-
}
107-
108-
impl<C: EllipticCurve> Add for AffinePoint<C> {
109-
type Output = AffinePoint<C>;
110-
111-
fn add(self, rhs: Self) -> Self::Output {
112-
// infty checks
113-
match (self, rhs) {
114-
(AffinePoint::Infinity, _) => return rhs,
115-
(_, AffinePoint::Infinity) => return self,
116-
117-
_ => (),
118-
}
119-
let (x1, y1) = match self {
120-
AffinePoint::PointOnCurve(x, y) => (x, y),
121-
AffinePoint::Infinity => unreachable!(),
122-
};
123-
let (x2, y2) = match rhs {
124-
AffinePoint::PointOnCurve(x, y) => (x, y),
125-
AffinePoint::Infinity => unreachable!(),
126-
};
127-
if x1 == x2 && y1 == -y2 {
128-
return AffinePoint::Infinity;
130+
fn mul(self, val: AffinePoint<C>) -> Self::Output {
131+
let mut out = val;
132+
for _ in 1..self {
133+
out += val;
129134
}
130-
// compute new point using elliptic curve point group law
131-
// https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication
132-
let lambda = if x1 == x2 && y1 == y2 {
133-
((C::BaseField::ONE + C::BaseField::ONE + C::BaseField::ONE) * x1 * x1 + C::EQUATION_A.into())
134-
/ ((C::BaseField::ONE + C::BaseField::ONE) * y1)
135-
} else {
136-
(y2 - y1) / (x2 - x1)
137-
};
138-
let x = lambda * lambda - x1 - x2;
139-
let y = lambda * (x1 - x) - y1;
140-
AffinePoint::new(x, y)
135+
out
141136
}
142137
}
143138

@@ -146,11 +141,12 @@ impl<C: EllipticCurve> AffinePoint<C> {
146141
/// Compute the point doubling operation on this point.
147142
pub fn point_doubling(self) -> AffinePoint<C> {
148143
let (x, y) = match self {
149-
AffinePoint::PointOnCurve(x, y) => (x, y),
150-
AffinePoint::Infinity => panic!("Cannot double point at infinity"),
144+
AffinePoint::Point(x, y) => (x, y),
145+
AffinePoint::Infinity => return AffinePoint::Infinity,
151146
};
152147
// m = (3x^2) / (2y)
153-
let m = (((C::BaseField::ONE + C::BaseField::ONE) + C::BaseField::ONE) * x * x)
148+
let m = (((C::BaseField::ONE + C::BaseField::ONE) + C::BaseField::ONE) * x * x
149+
+ C::EQUATION_A.into())
154150
/ ((C::BaseField::ONE + C::BaseField::ONE) * y);
155151

156152
// 2P = (m^2 - 2x, m(3x - m^2)- y)

0 commit comments

Comments
 (0)