# x25519

python有两个实现

https://gist.github.com/nickovs/cc3c22d15f239a2640c185035c06f8a3

```"""A pure Python implementation of Curve25519

This module supports both a low-level interface through curve25519(base_point, secret)
and curve25519_base(secret) that take 32-byte blocks of data as inputs and a higher
level interface using the X25519PrivateKey and X25519PublicKey classes that are
compatible with the classes in cryptography.hazmat.primitives.asymmetric.x25519 with
the same names.
"""

# By Nicko van Someren, 2021. This code is released into the public domain.

#                                  #### WARNING ####

# Since this code makes use of Python's built-in large integer types, it is NOT EXPECTED
# to run in constant time. While some effort is made to minimise the time variations,
# the underlying math functions are likely to have running times that are highly
# value-dependent, leaving this code potentially vulnerable to timing attacks. If this
# code is to be used to provide cryptographic security in an environment where the start
# and end times of the execution can be guessed, inferred or measured then it is critical
# that steps are taken to hide the execution time, for instance by adding a delay so that
# encrypted packets are not sent until a fixed time after the _start_ of execution.

# Implements ladder multiplication as described in "Montgomery curves and the Montgomery
# ladder" by Daniel J. Bernstein and Tanja Lange. https://eprint.iacr.org/2017/293.pdf

# Curve25519 is a Montgomery curve defined by:
# y**2 = x**3 + A * x**2 + x  mod P
# where P = 2**255-19 and A = 486662

P = 2 ** 255 - 19
_A = 486662

"""Given the projection of two points and their difference, return their sum"""
(xn, zn) = point_n
(xm, zm) = point_m
(x_diff, z_diff) = point_diff
x = (z_diff << 2) * (xm * xn - zm * zn) ** 2
z = (x_diff << 2) * (xm * zn - zm * xn) ** 2
return x % P, z % P

def _point_double(point_n):
"""Double a point provided in projective coordinates"""
(xn, zn) = point_n
xn2 = xn ** 2
zn2 = zn ** 2
x = (xn2 - zn2) ** 2
xzn = xn * zn
z = 4 * xzn * (xn2 + _A * xzn + zn2)
return x % P, z % P

def _const_time_swap(a, b, swap):
"""Swap two values in constant time"""
index = int(swap) * 2
temp = (a, b, b, a)
return temp[index:index+2]

def _raw_curve25519(base, n):
"""Raise the point base to the power n"""
zero = (1, 0)
one = (base, 1)
mP, m1P = zero, one

for i in reversed(range(256)):
bit = bool(n & (1 << i))
mP, m1P = _const_time_swap(mP, m1P, bit)
mP, m1P = _point_double(mP), _point_add(mP, m1P, one)
mP, m1P = _const_time_swap(mP, m1P, bit)

x, z = mP
inv_z = pow(z, P - 2, P)
return (x * inv_z) % P

def _unpack_number(s):
"""Unpack 32 bytes to a 256 bit value"""
if len(s) != 32:
raise ValueError('Curve25519 values must be 32 bytes')
return int.from_bytes(s, "little")

def _pack_number(n):
"""Pack a value into 32 bytes"""
return n.to_bytes(32, "little")

def _fix_secret(n):
"""Mask a value to be an acceptable exponent"""
n &= ~7
n &= ~(128 << 8 * 31)
n |= 64 << 8 * 31
return n

def curve25519(base_point_raw, secret_raw):
"""Raise the base point to a given power"""
base_point = _unpack_number(base_point_raw)
secret = _fix_secret(_unpack_number(secret_raw))
return _pack_number(_raw_curve25519(base_point, secret))

def curve25519_base(secret_raw):
"""Raise the generator point to a given power"""
secret = _fix_secret(_unpack_number(secret_raw))
return _pack_number(_raw_curve25519(9, secret))

class X25519PublicKey:
def __init__(self, x):
self.x = x

@classmethod
def from_public_bytes(cls, data):
return cls(_unpack_number(data))

def public_bytes(self):
return _pack_number(self.x)

class X25519PrivateKey:
def __init__(self, a):
self.a = a

@classmethod
def from_private_bytes(cls, data):
return cls(_fix_secret(_unpack_number(data)))

def private_bytes(self):
return _pack_number(self.a)

def public_key(self):
return _pack_number(_raw_curve25519(9, self.a))

def exchange(self, peer_public_key):
if isinstance(peer_public_key, bytes):
peer_public_key = X25519PublicKey.from_public_bytes(peer_public_key)
return _pack_number(_raw_curve25519(peer_public_key.x, self.a))

```

```from binascii import hexlify, unhexlify
from curve25519 import X25519PrivateKey

private_key     = unhexlify('')
peer_public_key = unhexlify('')

x25519x = X25519PrivateKey.from_private_bytes(private_key)

shared_secret = x25519x.exchange(peer_public_key)

print(hexlify(shared_secret))
```

https://github.com/1ocalhost/x25519

```from binascii import hexlify, unhexlify
import x25519

private_key    = unhexlify('')
public_key = x25519.scalar_base_mult(private_key)
print(hexlify(public_key))

peer_public_key = unhexlify('')
shared_secret = x25519.scalar_mult(private_key, peer_public_key)
print(hexlify(shared_secret))
```

```aaa = x25519.djbec.genkey()
bbb = x25519.djbec.encodeint(aaa)
print('priv=', hexlify(bbb))
```

rust

```use rand_core::{OsRng, RngCore};
use x25519_dalek::{EphemeralSecret, StaticSecret, PublicKey,  x25519};

use hex::FromHex;

fn main() {

//let alice_secret = StaticSecret::new(OsRng);
//let alice_secret = StaticSecret::random_from_rng(&mut OsRng);

let mut x4 = [0u8; 32];
let _ = hex::decode_to_slice("", &mut x4 as &mut [u8]).unwrap();
let alice_secret = StaticSecret::from(x4);

let xxx = alice_secret.to_bytes();
println!("alice secret={}", hex::encode_upper(&xxx));

let alice_public = PublicKey::from(&alice_secret);

// let bob_secret = StaticSecret::new(OsRng);
//     let bob_secret = StaticSecret::random_from_rng(&mut OsRng);
//let tmp = hex::decode("").unwrap();
//let x4: [u8; 32] = (&tmp[..]).try_into().unwrap();
let x4 = <[u8; 32]>::from_hex("").unwrap();

let bob_secret = StaticSecret::from(x4);
let bob_public = PublicKey::from(&bob_secret);

let yyy = bob_secret.to_bytes();
println!("bob secret={}", hex::encode_upper(&yyy));

let zzz = bob_public.to_bytes();
println!("bob public={}", hex::encode_upper(&zzz));

//let alice_shared_secret = alice_secret.diffie_hellman(&bob_public);
//let bob_shared_secret = bob_secret.diffie_hellman(&alice_public);
let alice_shared = x25519(xxx, zzz);
let bob_shared = x25519(yyy, alice_public.to_bytes());

assert_eq!(alice_shared, bob_shared);

println!("shared={}", hex::encode_upper(&alice_shared));

}
```