use crate::*;
use zeroize::{Zeroize, ZeroizeOnDrop};
use libsodium_sys::*;
use std::fmt;
#[derive(Clone, PartialEq)]
pub struct Keypair {
pub public: [u8; PUBLICKEYBYTES],
secret: SecretKey,
pub curve: Curve
}
#[derive(Clone, PartialEq, Zeroize, ZeroizeOnDrop)]
struct SecretKey([u8; SCALARBYTES]);
impl Keypair {
pub fn new(curve: Curve) -> Self {
let mut public = [0u8; BYTES];
let mut secret = SecretKey([0u8; SECRETKEYBYTES]);
unsafe {
match curve {
Curve::Ed25519 => {
crypto_core_ed25519_scalar_random(secret.0.as_mut_ptr());
crypto_scalarmult_ed25519_base_noclamp(public.as_mut_ptr(), secret.0.as_ptr());
},
Curve::Ristretto255 => {
crypto_core_ristretto255_scalar_random(secret.0.as_mut_ptr());
crypto_scalarmult_ristretto255_base(public.as_mut_ptr(), secret.0.as_ptr());
}
}
}
Self {public, secret, curve}
}
pub fn expose_secret(&self) -> &[u8; SCALARBYTES] {
&self.secret.0
}
pub fn from_secret(secret_bytes: [u8; SECRETKEYBYTES], curve: Curve) -> Self {
let mut public = [0u8; BYTES];
let secret = SecretKey(secret_bytes);
unsafe {
match curve {
Curve::Ed25519 => {
crypto_scalarmult_ed25519_base_noclamp(public.as_mut_ptr(), secret.0.as_ptr());
},
Curve::Ristretto255 => {
crypto_scalarmult_ristretto255_base(public.as_mut_ptr(), secret.0.as_ptr());
}
}
}
Self{public, secret, curve}
}
pub fn from_seed(seed: &[u8; SEEDBYTES], curve: Curve) -> Self {
let mut public = [0u8; BYTES];
let mut secret = SecretKey([0u8; SECRETKEYBYTES]);
unsafe {
match curve {
Curve::Ed25519 => {
crypto_core_ed25519_scalar_reduce(secret.0.as_mut_ptr(), seed.as_ptr());
crypto_scalarmult_ed25519_base_noclamp(public.as_mut_ptr(), secret.0.as_ptr());
},
Curve::Ristretto255 => {
crypto_core_ristretto255_scalar_reduce(secret.0.as_mut_ptr(), seed.as_ptr());
crypto_scalarmult_ristretto255_base(public.as_mut_ptr(), secret.0.as_ptr());
}
}
}
Keypair { public, secret, curve }
}
}
impl Default for Keypair {
fn default() -> Self {
Keypair::new(Curve::Ristretto255)
}
}
impl fmt::Debug for Keypair {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Curve: {:?}\nPublic Key: {}\nSecret Key: <Elided>",
self.curve, encode_hex(&self.public)
)
}
}
fn encode_hex(bytes: &[u8]) -> String {
let mut output = String::with_capacity(bytes.len() * 2);
for b in bytes {
output.push_str(&format!("{:02X}", b));
}
output
}