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