Skip to content

Commit c86305b

Browse files
committed
Finished implementation of secp256k1
1 parent 7a465cd commit c86305b

File tree

13 files changed

+177
-19
lines changed

13 files changed

+177
-19
lines changed

src/math/ec/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,31 @@ use super::field::FiniteField;
44

55
pub mod secp256k1;
66

7+
/// Trait that defines an elliptic curve point using certain number of limbs for the scalar and
8+
/// prime field.
79
pub trait EllipticCurve<const LIMBS: usize>: Serialize + for<'a> Deserialize<'a> {
810
type ScalarField: FiniteField<LIMBS>;
11+
12+
/// Field in which the elliptic curve is defined. The points in the elliptic curve will be
13+
/// pairs in this field.
914
type PrimeField: FiniteField<LIMBS>;
1015

16+
/// Returns the generator of the curve.
1117
fn gen() -> Self;
18+
19+
/// Computes the group addition between two points in the elliptic curve.
1220
fn add(&self, rhs: &Self) -> Self;
21+
22+
/// Computes the subtraction between two elements in the elliptic curve.
1323
fn sub(&self, rhs: &Self) -> Self;
24+
25+
/// Computes the multiplication by an scalar between an element in the scalar field and an
26+
/// point in the elliptic curve.
1427
fn scalar_mul(&self, rhs: &Self::ScalarField) -> Self;
28+
29+
/// Returns whether two points in the elliptic curve are equal.
1530
fn eq(&self, other: &Self) -> bool;
31+
32+
/// Returns the additive inverse of the point in the elliptic curve.
1633
fn negate(&self) -> Self;
1734
}

src/math/ec/secp256k1.rs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::ops::Mul;
1+
use std::ops::{Add, Mul};
22

33
use crypto_bigint::Uint;
44
use serde::{Deserialize, Serialize};
@@ -24,6 +24,23 @@ pub struct Secp256k1(
2424
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
2525
pub struct AffinePoint(Secp256k1PrimeField, Secp256k1PrimeField);
2626

27+
impl AffinePoint {
28+
pub fn x(&self) -> &Secp256k1PrimeField {
29+
&self.0
30+
}
31+
32+
pub fn y(&self) -> &Secp256k1PrimeField {
33+
&self.1
34+
}
35+
36+
pub fn is_valid(&self) -> bool {
37+
let b = Secp256k1PrimeField::from(7);
38+
let lhs = self.y().mul(self.y());
39+
let rhs = self.x().mul(self.x()).mul(self.x()).add(&b);
40+
lhs.eq(&rhs)
41+
}
42+
}
43+
2744
impl Secp256k1 {
2845
/// Point at infinity using affine coordinates.
2946
pub const POINT_AT_INFINITY: Self = Self(
@@ -52,7 +69,7 @@ impl Secp256k1 {
5269
if self.z().eq(&Secp256k1PrimeField::ONE) {
5370
AffinePoint(*self.x(), *self.y())
5471
} else {
55-
// TODO: Check the safety of this unwrap.
72+
assert!(!(self.z() == &Secp256k1PrimeField::ZERO));
5673
let z = self.z().inverse().unwrap();
5774
AffinePoint(self.x().mul(&z), self.y().mul(&z))
5875
}
@@ -89,6 +106,7 @@ impl Secp256k1 {
89106
t1 = *self.x() * self.y();
90107
x3 = t0 * &t1;
91108
x3 = x3 + &x3;
109+
92110
Self(x3, y3, z3)
93111
}
94112
}
@@ -99,10 +117,10 @@ impl EllipticCurve<4> for Secp256k1 {
99117

100118
fn gen() -> Self {
101119
Self(
102-
Secp256k1PrimeField::new(Uint::from_le_hex(
120+
Secp256k1PrimeField::new(Uint::from_be_hex(
103121
"79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
104122
)),
105-
Secp256k1PrimeField::new(Uint::from_le_hex(
123+
Secp256k1PrimeField::new(Uint::from_be_hex(
106124
"483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
107125
)),
108126
Secp256k1PrimeField::ONE,
@@ -180,7 +198,7 @@ impl EllipticCurve<4> for Secp256k1 {
180198
let mut result = Self::POINT_AT_INFINITY;
181199
let naf = scalar.to_naf();
182200
for i in (0..naf.len()).rev() {
183-
result = self.dbl();
201+
result = result.dbl();
184202
if naf.pos(i) {
185203
result = result.add(self);
186204
} else if naf.neg(i) {

src/math/field/mersenne61.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ impl Ring for Mersenne61 {
4040
Self::from(value)
4141
}
4242

43+
fn random_non_zero<R: RngCore>(generator: &mut R) -> Self {
44+
let mut value = generator.next_u64();
45+
while value == 0 {
46+
value = generator.next_u64();
47+
}
48+
Self::from(value)
49+
}
50+
4351
fn negate(&self) -> Self {
4452
if !self.eq(&Self::ZERO) {
4553
Self::from(u64::from(Self::MODULUS.to_limbs()[0]) - self.0)

src/math/field/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub mod secp256k1_prime;
1212

1313
pub mod secp256k1_scalar;
1414

15-
mod naf;
15+
pub mod naf;
1616

1717
/// Errors for mathematical operations between field elements.
1818
#[derive(Error, Debug)]

src/math/field/naf.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1-
/// Representation of a NAF encoding. The encoding is done in the following way:
1+
/// Representation of a non-adjacent form (NAF) encoding. The encoding is done in the following way:
22
/// - Value 1 is encoded as 1 inside the array,
33
/// - Value 0 is encoded as 0 inside the array,
44
/// - Value -1 is encoded as 2 inside the array.
5+
#[derive(Eq, PartialEq, Debug)]
56
pub struct NafEncoding(Vec<u8>);
67

78
impl NafEncoding {
9+
/// Returns the length of the representation.
810
pub fn len(&self) -> usize {
911
self.0.len()
1012
}
1113

14+
/// Creates a new NAF representation using a given maximum number of digits.
1215
pub fn new(capacity: usize) -> Self {
1316
Self(vec![0; capacity])
1417
}

src/math/field/secp256k1_prime.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ impl Ring for Secp256k1PrimeField {
5555
let value = Uint::<4>::random_mod(generator, &Self::MODULUS);
5656
Self(value)
5757
}
58+
59+
fn random_non_zero<R: RngCore>(generator: &mut R) -> Self {
60+
let mut value = Uint::<4>::random_mod(generator, &Self::MODULUS);
61+
while bool::from(value.is_zero()) {
62+
value = Uint::<4>::random_mod(generator, &Self::MODULUS);
63+
}
64+
Self(value)
65+
}
5866
}
5967

6068
impl Add<&Self> for Secp256k1PrimeField {

src/math/field/secp256k1_scalar.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl From<u64> for Secp256k1ScalarField {
7474
}
7575

7676
impl Ring for Secp256k1ScalarField {
77-
const BIT_SIZE: usize = Self::LIMBS * u64::BITS as usize;
77+
const BIT_SIZE: usize = Self::LIMBS * Limb::BITS as usize;
7878
const ZERO: Self = Self(Uint::ZERO);
7979
const ONE: Self = Self(Uint::ONE);
8080
const LIMBS: usize = 4;
@@ -87,6 +87,14 @@ impl Ring for Secp256k1ScalarField {
8787
let value = Uint::<4>::random_mod(generator, &Self::MODULUS);
8888
Self(value)
8989
}
90+
91+
fn random_non_zero<R: RngCore>(generator: &mut R) -> Self {
92+
let mut value = Uint::<4>::random_mod(generator, &Self::MODULUS);
93+
while bool::from(value.is_zero()) {
94+
value = Uint::<4>::random_mod(generator, &Self::MODULUS);
95+
}
96+
Self(value)
97+
}
9098
}
9199

92100
impl Add<&Self> for Secp256k1ScalarField {

src/math/ring.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,6 @@ pub trait Ring:
3636

3737
/// Generates a random finite ring element with a provided pseudo-random generator.
3838
fn random<R: RngCore>(generator: &mut R) -> Self;
39+
40+
fn random_non_zero<R: RngCore>(generator: &mut R) -> Self;
3941
}

tests/mersenne61.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ fn subract() {
5454
fn inverse() {
5555
const SAMPLES: usize = 100;
5656
for _ in 0..SAMPLES {
57-
let elem = Mersenne61::random(&mut OsRng);
57+
let elem = Mersenne61::random_non_zero(&mut OsRng);
5858
let s = elem.mul(&elem.inverse().unwrap());
5959
assert_eq!(s, Mersenne61::ONE);
6060
}

tests/naf.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use scl_rs::math::{
2+
field::{naf::NafEncoding, secp256k1_scalar::Secp256k1ScalarField},
3+
ring::Ring,
4+
};
5+
6+
#[test]
7+
fn fixed_naf() {
8+
let naf = Secp256k1ScalarField::ZERO.to_naf();
9+
assert_eq!(NafEncoding::new(Secp256k1ScalarField::BIT_SIZE + 1), naf);
10+
11+
let naf = Secp256k1ScalarField::from(13).to_naf();
12+
let mut true_naf = NafEncoding::new(Secp256k1ScalarField::BIT_SIZE + 1);
13+
true_naf.create_pos(0);
14+
true_naf.create_pos(4);
15+
true_naf.create_neg(2);
16+
assert_eq!(naf, true_naf);
17+
18+
let naf = Secp256k1ScalarField::from(213).to_naf();
19+
let mut true_naf = NafEncoding::new(Secp256k1ScalarField::BIT_SIZE + 1);
20+
true_naf.create_pos(0);
21+
true_naf.create_pos(2);
22+
true_naf.create_pos(4);
23+
true_naf.create_pos(8);
24+
true_naf.create_neg(6);
25+
assert_eq!(naf, true_naf);
26+
}

0 commit comments

Comments
 (0)