almost working
This commit is contained in:
commit
14cfa2efb0
9 changed files with 390 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/target
|
||||
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
11
.idea/diffie-hellman.iml
generated
Normal file
11
.idea/diffie-hellman.iml
generated
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="EMPTY_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/diffie-hellman.iml" filepath="$PROJECT_DIR$/.idea/diffie-hellman.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
80
Cargo.lock
generated
Normal file
80
Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-bigint"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96272c2ff28b807e09250b180ad1fb7889a3258f7455759b5c3c58b719467130"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"rand_core",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diffie-hellman"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"crypto-bigint",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.176"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.1+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||
7
Cargo.toml
Normal file
7
Cargo.toml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "diffie-hellman"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
crypto-bigint = { version = "0.6.1", features = ["rand"] }
|
||||
250
src/lib.rs
Normal file
250
src/lib.rs
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
use std::fmt::{Display, Formatter, Write};
|
||||
use crypto_bigint::{Encoding, MulMod, NonZero, Odd, Random, U256};
|
||||
use std::ops::Mul;
|
||||
use crypto_bigint::rand_core::OsRng;
|
||||
|
||||
pub fn add(left: u64, right: u64) -> u64 {
|
||||
left + right
|
||||
}
|
||||
|
||||
/// By^2 = x^3 + Ax^2 + x
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct MontgomeryCurve {
|
||||
pub a: U256,
|
||||
pub b: U256,
|
||||
pub p: U256,
|
||||
}
|
||||
|
||||
impl MontgomeryCurve {
|
||||
pub const fn new(a: U256, b: U256, p: U256) -> MontgomeryCurve {
|
||||
MontgomeryCurve { a, b, p }
|
||||
}
|
||||
|
||||
pub fn y(&self, x: U256) -> U256 {
|
||||
((x*x*x + self.a*x*x + x)/self.b).sqrt()
|
||||
}
|
||||
|
||||
pub fn point(self, x: U256) -> MontgomeryPoint {
|
||||
MontgomeryPoint{
|
||||
x,
|
||||
z: U256::ONE,
|
||||
curve: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clamp_u256(x: U256) -> U256 {
|
||||
let mut words: [u8; 32] = x.to_le_bytes();
|
||||
|
||||
// clamp value
|
||||
words[0] &= 0b1111_1000;
|
||||
words[31] &= 0b0111_1111;
|
||||
words[31] |= 0b0100_0000;
|
||||
|
||||
|
||||
U256::from_le_bytes(words)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct MontgomeryPoint {
|
||||
x: U256,
|
||||
z: U256,
|
||||
|
||||
curve: MontgomeryCurve,
|
||||
}
|
||||
|
||||
impl MontgomeryPoint {
|
||||
pub fn add(&self, rhs: MontgomeryPoint, neg: MontgomeryPoint) -> MontgomeryPoint {
|
||||
let p = &NonZero::new(CURVE_25519.p).unwrap();
|
||||
|
||||
let mut v_0 = self.x + self.z; // 1: V_0 = X_P + Z_P
|
||||
let mut v_1 = rhs.x.wrapping_sub(&rhs.z); // 2: V_1 = X_Q - Z_Q
|
||||
v_1 = v_1.mul_mod(&v_0, p); // 3: V_1 = V_1 * V_0
|
||||
|
||||
v_0 = self.x.sub_mod(&self.z, p); // 4: V_0 = X_P - Z_P
|
||||
let mut v_2 = rhs.x.add_mod(&rhs.z, p); // 5: V_2 = X_Q + Z_Q
|
||||
v_2 = v_2.mul_mod(&v_0, p); // 6: V_2 = V_2 * V_0
|
||||
|
||||
let mut v_3 = v_1 + v_2; // 7: V_3 = V_1 + V_2
|
||||
v_3 = v_3.mul_mod(&v_3, p); // 8: V_3 = V_3^2
|
||||
|
||||
let mut v_4 = v_1.sub_mod(&v_2, p); // 9: V_4 = V_1 - V_2
|
||||
v_4 = v_4.mul_mod(&v_4, p); // 10:
|
||||
|
||||
let x = neg.z.mul_mod(&v_3, p); // 11: X_⨁ = Z_⊝ * V_3
|
||||
let z = neg.x.mul_mod(&v_4, p); // 12: Z_⨁ = X_⊝ * V_4
|
||||
|
||||
MontgomeryPoint {
|
||||
x,
|
||||
z,
|
||||
curve: self.curve,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn double(&self) -> MontgomeryPoint {
|
||||
let p = &NonZero::new(CURVE_25519.p).unwrap();
|
||||
|
||||
let mut v_1 = self.x.add_mod(&self.z, p);
|
||||
v_1 = v_1.mul_mod(&v_1, p);
|
||||
|
||||
let mut v_2 = self.x.sub_mod(&self.z, p);
|
||||
v_2 = v_2.mul_mod(&v_2, p);
|
||||
|
||||
let x_2p = v_1.mul_mod(&v_2, p);
|
||||
|
||||
v_1 = v_1.sub_mod(&v_2, p);
|
||||
let mut v_3 = ((self.curve.a + U256::from_u8(2))/U256::from_u8(4)).mul_mod(&v_1, p);
|
||||
|
||||
v_3 = v_3.add_mod(&v_2, p);
|
||||
|
||||
let z_2p = v_1.mul_mod(&v_3, p);
|
||||
|
||||
MontgomeryPoint {
|
||||
x: x_2p,
|
||||
z: z_2p,
|
||||
curve: self.curve,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_x(&self) -> U256 {
|
||||
let inv = self.z.inv_odd_mod(&Odd::new(CURVE_25519.p).unwrap());
|
||||
self.x.mul_mod(&inv.unwrap(), &NonZero::new(self.curve.p).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for MontgomeryPoint {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_fmt(format_args!("({} : {})", self.x, self.z))
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<U256> for MontgomeryPoint {
|
||||
type Output = MontgomeryPoint;
|
||||
|
||||
/// ~constant-time~ montgomery ladder
|
||||
fn mul(self, rhs: U256) -> Self::Output {
|
||||
let mut x_0 = self;
|
||||
let mut x_1 = x_0.double();
|
||||
|
||||
for i in (0..rhs.bits() - 2).rev() {
|
||||
if rhs.bit(i).into() {
|
||||
x_0 = x_0.double();
|
||||
x_1 = x_0.add(x_1, self);
|
||||
} else {
|
||||
x_0 = x_0.add(x_1, self);
|
||||
x_1 = x_1.double();
|
||||
}
|
||||
}
|
||||
|
||||
x_0
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
fn montgomery_ladder(x: U256, n: U256) -> U256 {
|
||||
let mut x_1 = x;
|
||||
let mut x_2 = U256::ONE;
|
||||
let mut z_2 = U256::ZERO;
|
||||
let mut x_3 = x;
|
||||
let mut z_3 = U256::ONE;
|
||||
|
||||
let mut prevbit = 0u8;
|
||||
|
||||
for i in (0..(n.bits()-1)).rev() {
|
||||
let bit = bool::from(n.bit(i)) as u8;
|
||||
let b = bit ^ prevbit;
|
||||
prevbit = bit;
|
||||
|
||||
// CSwap
|
||||
match b & 1 == 0 {
|
||||
true => {
|
||||
swap(&mut x_2, &mut x_3);
|
||||
swap(&mut z_2, &mut z_3);
|
||||
}
|
||||
false => {
|
||||
swap(&mut x_2, &mut x_3);
|
||||
swap(&mut x_2, &mut x_3);
|
||||
}
|
||||
}
|
||||
|
||||
//ladder_step(&mut x_2, &mut z_2, &mut x_3, &mut z_3, x_1);
|
||||
}
|
||||
|
||||
U256::ZERO
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/// from the curve: \
|
||||
/// $y^2 = x*(x^2 + 486662x + 1)$
|
||||
/// => A = 486662, B = 1, p = 2^255 - 19
|
||||
pub const CURVE_25519: MontgomeryCurve = MontgomeryCurve::new(
|
||||
U256::from_u32(486662u32),
|
||||
U256::ONE,
|
||||
U256::ONE.shl(255).sub_mod(&U256::from_u8(19), &U256::MAX),
|
||||
);
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Public(U256);
|
||||
|
||||
impl From<&Secret> for Public {
|
||||
fn from(s: &Secret) -> Public {
|
||||
let p = CURVE_25519.point(U256::from_u8(9));
|
||||
let x = (p * clamp_u256(s.0)).get_x();
|
||||
|
||||
Public(x)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
pub struct Secret(U256);
|
||||
|
||||
impl Secret {
|
||||
pub fn random() -> Secret {
|
||||
Secret::from(U256::random(&mut OsRng))
|
||||
}
|
||||
|
||||
pub fn diffie_hellman(&self, public: Public) -> Secret {
|
||||
let b = public.0; // public
|
||||
let a = self.0; // private
|
||||
|
||||
let p = CURVE_25519.point(b);
|
||||
let s = p * a;
|
||||
|
||||
Secret(s.get_x())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Secret {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_fmt(format_args!("{}", self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<U256> for Secret {
|
||||
fn from(value: U256) -> Self {
|
||||
Secret(clamp_u256(value))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn diffie_hellman() {
|
||||
let a = Secret::random();
|
||||
let b = Secret::random();
|
||||
|
||||
// Public keys
|
||||
let pa = Public::from(&a);
|
||||
let pb = Public::from(&b);
|
||||
|
||||
// Shared secret
|
||||
let sa = a.diffie_hellman(pb);
|
||||
let sb = b.diffie_hellman(pa);
|
||||
|
||||
assert_eq!(sa, sb);
|
||||
}
|
||||
}
|
||||
19
src/main.rs
Normal file
19
src/main.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
use crypto_bigint::rand_core::OsRng;
|
||||
use crypto_bigint::U256;
|
||||
use crypto_bigint::Random;
|
||||
use diffie_hellman::{Public, Secret, CURVE_25519};
|
||||
|
||||
fn main() {
|
||||
println!("{}", CURVE_25519.p);
|
||||
|
||||
let a = Secret::random();
|
||||
let b = Secret::random();
|
||||
|
||||
let A = Public::from(&a);
|
||||
let B = Public::from(&b);
|
||||
|
||||
let sa = a.diffie_hellman(B);
|
||||
let sb = b.diffie_hellman(A);
|
||||
|
||||
println!("{} == {}", sa, sb)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue