Skip to content

Commit

Permalink
Merge pull request #7 from 0xphen/feature/ecc
Browse files Browse the repository at this point in the history
ECC
  • Loading branch information
0xphen authored Dec 21, 2023
2 parents 95b0db0 + 73a1c37 commit 32c74b7
Show file tree
Hide file tree
Showing 9 changed files with 287 additions and 8 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ members = [
"sha-256",
"rsa",
"aes",
"ecc",
"utils"
]
4 changes: 2 additions & 2 deletions aes/src/aes_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ impl AesOps {
/// * `s_box` - The S-box used for the transformation, either standard or inverse.
fn sub_bytes(state: &mut [[u8; 4]; 4], s_box: [u8; 256]) {
// Iterate over each byte of the state matrix
for (i, row) in state.iter_mut().enumerate() {
for (j, e) in row.iter_mut().enumerate() {
for row in state.iter_mut() {
for e in row.iter_mut() {
// Apply the S-box transformation and store in `new_state`
*e = s_box[*e as usize];
}
Expand Down
7 changes: 2 additions & 5 deletions diffie-hellman-key-exchange/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use num_bigint::{BigUint, RandBigInt};
use num_traits::{Num, Pow};
use num_traits::Num;

// safe prime in RFC3526 https://datatracker.ietf.org/doc/rfc3526/
const SAFE_PRIME_HEX: &str = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF";
Expand Down Expand Up @@ -84,9 +84,6 @@ mod tests {

let bob_version_of_shared_secret = bob.calculate_shared_secret(&alice_public_key);

assert_eq!(
alice_version_of_shared_secret.eq(&bob_version_of_shared_secret),
true
);
assert!(alice_version_of_shared_secret.eq(&bob_version_of_shared_secret));
}
}
11 changes: 11 additions & 0 deletions ecc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "ecc"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
lazy_static = "1.4.0"
num-bigint = "0.4.4"
num-traits = "0.2.17"
32 changes: 32 additions & 0 deletions ecc/src/definitions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use num_bigint::BigInt;

// A tuple struct representing a point with two BigUint coordinates (x, y).

#[derive(PartialEq, Debug, Clone)]
pub struct Point(pub BigInt, pub BigInt);

/// Represents a point on an elliptic curve.
#[derive(PartialEq, Debug)]
pub enum EccPoint {
// A point with finite coordinates represented by a `Point` tuple struct.
Finite(Point),
// The point at infinity, acting as the identity element in elliptic curve arithmetic.
Infinity,
}

/// Represents the supported elliptic curves.
///
/// # Variants
/// * `Secp256k1` - Represents the secp256k1 curve.
pub enum Curve {
Secp256k1,
}

/// Defines the behavior for an elliptic curve.
pub trait EllipticCurve {
// Adds two points on the elliptic curve and returns the resulting point.
fn add_points(&self, a: &EccPoint, b: &EccPoint) -> EccPoint;

// Doubles a point on the elliptic curve.
fn double_point(&self, a: &EccPoint) -> EccPoint;
}
4 changes: 4 additions & 0 deletions ecc/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub mod definitions;
mod secp256k1;
pub mod util;

164 changes: 164 additions & 0 deletions ecc/src/secp256k1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
use std::ops::{Mul, Sub};

use num_bigint::BigInt;
use num_traits::{Num, One, Zero};

use super::{definitions::*, util::*};

pub const X: &str = "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798";
pub const Y: &str = "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8";
pub const N: &str = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F";
pub const A: &str = "0000000000000000000000000000000000000000000000000000000000000000";
pub const B: &str = "0000000000000000000000000000000000000000000000000000000000000007";

#[derive(PartialEq)]
pub struct SECP256K1 {
pub g: Point,
pub n: BigInt,
pub a: BigInt,
pub b: BigInt,
}

impl Default for SECP256K1 {
fn default() -> Self {
let x: BigInt =
BigInt::from_str_radix(X, 16).expect("Failed to parse Secp256k1-generator-x");

let y: BigInt =
BigInt::from_str_radix(Y, 16).expect("Failed to parse Secp256k1-generator-y");

let n: BigInt =
BigInt::from_str_radix(N, 16).expect("Failed to parse Secp256k1-group-order");

let a: BigInt = BigInt::from_str_radix(A, 16).expect("Failed to parse Secp256k1-a");

let b: BigInt = BigInt::from_str_radix(B, 16).expect("Failed to parse Secp256k1-b");

Self {
g: Point(x, y),
n,
a,
b,
}
}
}

impl EllipticCurve for SECP256K1 {
/// Doubles a point on an elliptic curve.
///
/// This function takes a point on the elliptic curve and returns a new point
/// that is the result of doubling the input point according to elliptic curve
/// arithmetic. The point doubling is done modulo the curve's defined prime field.
///
/// # Arguments
/// * `ecc_point` - A reference to `EccPoint`, which can either be a finite point
/// on the curve or the point at infinity.
///
/// # Returns
/// Returns `EccPoint`, which is either:
/// * A finite point resulting from the doubling operation.
/// * The point at infinity if the input is the point at infinity or if the result
/// of the doubling operation leads to the point at infinity (e.g., when the
/// y-coordinate of the input point is zero).
fn double_point(&self, ecc_point: &EccPoint) -> EccPoint {
match ecc_point {
EccPoint::Finite(point) => {
if point.1.is_zero() {
return EccPoint::Infinity;
}

let numerator = (BigInt::from(3u32) * (point.0).pow(2) + &self.a) % &self.n;

let denominator = BigInt::from(2u32) * &point.1;

// Slope
let slope = (numerator * mod_inv(&denominator, &self.n)) % &self.n;

let (x3, y3) =
derive_new_point_coordinates(&slope, &point.0, &point.0, &point.1, &self.n);

EccPoint::Finite(Point(x3, y3))
}

_ => EccPoint::Infinity,
}
}

/// Adds two points on an elliptic curve.
///
/// Handles the addition of finite points and points at infinity. If the points are inverses,
/// returns the point at infinity.
///
/// # Arguments
/// * `p1` - The first point as `EccPoint`.
/// * `p2` - The second point as `EccPoint`.
///
/// # Returns
/// The result of the addition as `EccPoint`.
fn add_points(&self, p1: &EccPoint, p2: &EccPoint) -> EccPoint {
match (p1, p2) {
(EccPoint::Finite(p1), EccPoint::Finite(p2)) => {
if points_inverse(p1, p2) {
return EccPoint::Infinity;
}

let numerator = (&p2.1 - &p1.1) % &self.n;
let denominator = &p2.0 - &p1.0;
let slope = (numerator * mod_inv(&denominator, &self.n)) % &self.n;

let (x3, y3) = derive_new_point_coordinates(&slope, &p1.0, &p2.0, &p1.1, &self.n);

EccPoint::Finite(Point(x3, y3))
}
(EccPoint::Finite(p1), EccPoint::Infinity) => EccPoint::Finite(p1.clone()),
(EccPoint::Infinity, EccPoint::Finite(p2)) => EccPoint::Finite(p2.clone()),
_ => EccPoint::Infinity,
}
}
}

#[cfg(test)]
mod tests {
use lazy_static::lazy_static;

use super::*;

lazy_static! {
static ref SECP256K1_CURVE: SECP256K1 = SECP256K1::default();
static ref MOCK_SECP256K1_CURVE: SECP256K1 = SECP256K1 {
g: Point(BigInt::from(5i32), BigInt::from(1i32),),
n: BigInt::from(17i32),
a: BigInt::from(2i32),
b: BigInt::from(2i32)
};
}

#[test]
fn double_point_test() {
let new_point = MOCK_SECP256K1_CURVE.double_point(&EccPoint::Finite(Point(
BigInt::from(5i32),
BigInt::from(1i32),
)));

assert!(new_point == EccPoint::Finite(Point(BigInt::from(6i32), BigInt::from(3i32))));
}

#[test]
fn add_points_test() {
let p1 = Point(BigInt::from(6i32), BigInt::from(3i32));
let p2 = Point(BigInt::from(5i32), BigInt::from(1i32));

let mut new_point = MOCK_SECP256K1_CURVE
.add_points(&EccPoint::Finite(p1.clone()), &EccPoint::Finite(p2.clone()));

assert!(new_point == EccPoint::Finite(Point(BigInt::from(10i32), BigInt::from(6i32))));

new_point =
MOCK_SECP256K1_CURVE.add_points(&EccPoint::Finite(p1.clone()), &EccPoint::Infinity);
assert!(new_point == EccPoint::Finite(p1));

new_point =
MOCK_SECP256K1_CURVE.add_points(&EccPoint::Infinity, &EccPoint::Finite(p2.clone()));
assert!(new_point == EccPoint::Finite(p2));
}
}
70 changes: 70 additions & 0 deletions ecc/src/util.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use std::ops::Add;

use num_bigint::BigInt;
use num_traits::Zero;

use super::definitions::Point;

/// Calculates the modular inverse of `a` modulo `m` using a modified version of Fermat's theorem.
pub fn mod_inv(a: &BigInt, m: &BigInt) -> BigInt {
a.modpow(&(m - BigInt::from(2i32)), m)
}

/// Checks if two points on an elliptic curve are inverses of each other.
pub fn points_inverse(a: &Point, b: &Point) -> bool {
a.0 == b.0 && (&a.1).add(&b.1).is_zero()
}

/// Calculates the new point coordinates for elliptic curve operations.
///
/// # Arguments
/// * `slope` - The slope of the line.
/// * `p1_x` - The x-coordinate of the first point.
/// * `p2_x` - The x-coordinate of the second point or same as `p1_x` for doubling.
/// * `p1_y` - The y-coordinate of the first point.
/// * `n` - The modulus for the finite field.
///
/// # Returns
/// A tuple `(x3, y3)` representing the new point coordinates.
pub fn derive_new_point_coordinates(
slope: &BigInt,
p1_x: &BigInt,
p2_x: &BigInt,
p1_y: &BigInt,
n: &BigInt,
) -> (BigInt, BigInt) {
let x3 = (slope.pow(2) - (p1_x + p2_x)) % n;

let mut y3 = (slope * (p1_x - &x3) - p1_y) % n;
if y3 < BigInt::zero() {
y3 += n;
}

(x3, y3)
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn mod_inv_test() {
let result = mod_inv(&BigInt::from(3i32), &BigInt::from(11i32));
assert_eq!(result, BigInt::from(4i32));
}

#[test]
fn points_inverse_test() {
let a = BigInt::from(1i32);
let b = BigInt::from(2i32);

let mut is_inverse =
points_inverse(&Point(a.clone(), b.clone()), &Point(a.clone(), -b.clone()));

assert!(is_inverse);

is_inverse = points_inverse(&Point(a.clone(), b.clone()), &Point(a, b));

assert!(!is_inverse)
}
}
2 changes: 1 addition & 1 deletion rsa/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ impl RSA {
// Create BigInt from the constant exponent.
let e = BigInt::from(E);

// Check if e and phi_n are coprime, which they should be by the choice of e.
// Check if e and phi_n are co-prime, which they should be by the choice of e.
if !relative_prime::is_co_prime(&phi_n, &e) {
panic!("{} and {} are not co-prime", e, phi_n);
}
Expand Down

0 comments on commit 32c74b7

Please sign in to comment.