use std::convert::From;
use crate::util::hash_i_padding;
use crate::xeddsa::*;
use curve25519_dalek::edwards::EdwardsPoint;
use curve25519_dalek::montgomery::MontgomeryPoint;
use curve25519_dalek::scalar::{clamp_integer, Scalar};
use ed25519::Signature;
use ed25519_dalek::{Verifier, VerifyingKey};
use x25519_dalek;
use rand::CryptoRng;
use sha2::{Digest, Sha512};
use zeroize::{Zeroize, ZeroizeOnDrop};
const PRIVATE_KEY_LENGTH: usize = 32;
const PUBLIC_KEY_LENGTH: usize = 32;
const SIGNATURE_LENGTH: usize = 64;
#[derive(Zeroize, ZeroizeOnDrop)]
pub struct PrivateKey(
pub [u8; PRIVATE_KEY_LENGTH],
);
pub struct PublicKey(
pub [u8; PUBLIC_KEY_LENGTH],
);
impl CalculateKeyPair<[u8; PRIVATE_KEY_LENGTH], [u8; PUBLIC_KEY_LENGTH]> for PrivateKey {
fn calculate_key_pair(&self, sign: u8) -> ([u8; PRIVATE_KEY_LENGTH], [u8; PUBLIC_KEY_LENGTH]) {
let clamped = clamp_integer(self.0);
let scalar_private_key = Scalar::from_bytes_mod_order(clamped);
let point_public_key = EdwardsPoint::mul_base(&scalar_private_key);
if (point_public_key.compress().to_bytes()[31] & 0x80) >> 7 == sign {
(clamped, point_public_key.compress().to_bytes())
} else {
let scalar_private_key = (Scalar::ZERO - Scalar::from(1_u8)) * scalar_private_key;
let point_public_key = EdwardsPoint::mul_base(&scalar_private_key);
(
scalar_private_key.to_bytes(),
point_public_key.compress().to_bytes(),
)
}
}
}
impl Sign<[u8; SIGNATURE_LENGTH], [u8; PRIVATE_KEY_LENGTH], [u8; PUBLIC_KEY_LENGTH]> for PrivateKey
where
PrivateKey: CalculateKeyPair<[u8; PRIVATE_KEY_LENGTH], [u8; PUBLIC_KEY_LENGTH]>,
{
fn sign(&self, message: &[u8], mut rng: impl CryptoRng) -> [u8; SIGNATURE_LENGTH] {
let (private_key, public_key) = self.calculate_key_pair(0);
let mut nonce = [0u8; 64];
rng.fill_bytes(&mut nonce);
let padding: [u8; 32] = hash_i_padding(1);
let mut hasher = Sha512::new();
hasher.update(padding);
hasher.update(private_key);
hasher.update(message);
hasher.update(nonce);
let res: [u8; 64] = hasher.finalize().into();
let res_scalar = Scalar::from_bytes_mod_order_wide(&res);
let res_point = EdwardsPoint::mul_base(&res_scalar);
let mut hasher = Sha512::new();
hasher.update(res_point.compress().to_bytes());
hasher.update(public_key);
hasher.update(message);
let hash: [u8; 64] = hasher.finalize().into();
let hash_scalar = Scalar::from_bytes_mod_order_wide(&hash);
let private_scalar = Scalar::from_bytes_mod_order(private_key);
let salt = res_scalar + hash_scalar * private_scalar;
let mut signature = [0u8; SIGNATURE_LENGTH];
signature[0..32].copy_from_slice(&res_point.compress().to_bytes());
signature[32..64].copy_from_slice(&salt.to_bytes());
signature
}
}
impl Sign<Signature, [u8; PRIVATE_KEY_LENGTH], [u8; PUBLIC_KEY_LENGTH]> for PrivateKey
where
PrivateKey: CalculateKeyPair<[u8; PRIVATE_KEY_LENGTH], [u8; PUBLIC_KEY_LENGTH]>,
{
fn sign(&self, message: &[u8], rng: impl CryptoRng) -> Signature {
Signature::from_bytes(&self.sign(message, rng))
}
}
impl From<&[u8; PRIVATE_KEY_LENGTH]> for PrivateKey {
fn from(value: &[u8; PRIVATE_KEY_LENGTH]) -> PrivateKey {
let mut value_c: [u8; PRIVATE_KEY_LENGTH] = [0u8; PRIVATE_KEY_LENGTH];
value_c.copy_from_slice(value);
PrivateKey(value_c)
}
}
impl From<&x25519_dalek::StaticSecret> for PrivateKey {
fn from(value: &x25519_dalek::StaticSecret) -> PrivateKey {
PrivateKey::from(&value.to_bytes())
}
}
impl From<PrivateKey> for [u8; PRIVATE_KEY_LENGTH] {
fn from(value: PrivateKey) -> [u8; PRIVATE_KEY_LENGTH] {
value.0
}
}
impl ConvertMont<[u8; PUBLIC_KEY_LENGTH]> for PublicKey {
fn convert_mont(&self, sign: u8) -> Result<[u8; PUBLIC_KEY_LENGTH], Error> {
let edwards_point = MontgomeryPoint(self.0)
.to_edwards(sign)
.ok_or(Error::UnusablePublicKey)?;
Ok(edwards_point.compress().to_bytes())
}
}
impl Verify<Signature, [u8; PUBLIC_KEY_LENGTH]> for PublicKey
where
PublicKey: ConvertMont<[u8; PUBLIC_KEY_LENGTH]>,
{
fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), Error> {
let public_key = self.convert_mont(0)?;
let verifying_key =
VerifyingKey::from_bytes(&public_key).or(Err(Error::UnusablePublicKey))?;
verifying_key
.verify(message, signature)
.or(Err(Error::InvalidSignature))
}
}
impl Verify<[u8; SIGNATURE_LENGTH], [u8; PUBLIC_KEY_LENGTH]> for PublicKey
where
PublicKey: ConvertMont<[u8; PUBLIC_KEY_LENGTH]>,
{
fn verify(&self, message: &[u8], signature: &[u8; SIGNATURE_LENGTH]) -> Result<(), Error> {
self.verify(message, &Signature::from_bytes(signature))
}
}
impl From<&x25519_dalek::PublicKey> for PublicKey {
fn from(value: &x25519_dalek::PublicKey) -> PublicKey {
PublicKey(value.to_bytes())
}
}