use crate::inner_types::*;
use crate::{util::*, Token};
use core::convert::TryFrom;
use rand_core::*;
use serde::{Deserialize, Serialize};
use subtle::{Choice, ConstantTimeEq, CtOption};
use zeroize::ZeroizeOnDrop;
#[derive(Clone, Debug, Eq, Deserialize, Serialize, ZeroizeOnDrop)]
#[zeroize(drop)]
pub struct SecretKey {
pub(crate) w: Scalar,
pub(crate) x: Scalar,
pub(crate) y: Scalar,
}
impl Default for SecretKey {
fn default() -> Self {
Self {
w: Scalar::ZERO,
x: Scalar::ZERO,
y: Scalar::ZERO,
}
}
}
impl From<&[u8; SecretKey::BYTES]> for SecretKey {
fn from(data: &[u8; Self::BYTES]) -> Self {
Self::from_bytes(data).unwrap()
}
}
impl PartialEq for SecretKey {
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).unwrap_u8() == 1
}
}
impl ConstantTimeEq for SecretKey {
fn ct_eq(&self, rhs: &Self) -> Choice {
self.x.ct_eq(&rhs.x) & self.y.ct_eq(&rhs.y) & self.w.ct_eq(&rhs.w)
}
}
#[cfg(feature = "wasm")]
wasm_slice_impl!(SecretKey);
impl SecretKey {
pub const BYTES: usize = 96;
pub fn new(mut rng: impl RngCore + CryptoRng) -> Self {
Self {
w: Scalar::random(&mut rng),
x: Scalar::random(&mut rng),
y: Scalar::random(&mut rng),
}
}
pub fn hash(data: &[u8]) -> Self {
let mut values = [Scalar::ZERO; 3];
hash_to_scalars(&[data], &mut values);
Self {
w: values[0],
x: values[1],
y: values[2],
}
}
pub fn to_bytes(&self) -> [u8; Self::BYTES] {
let mut out = [0u8; Self::BYTES];
out[..32].copy_from_slice(&self.w.to_le_bytes()[..]);
out[32..64].copy_from_slice(&self.x.to_le_bytes()[..]);
out[64..].copy_from_slice(&self.y.to_le_bytes()[..]);
out
}
pub fn from_bytes(data: &[u8; Self::BYTES]) -> CtOption<Self> {
let ww = Scalar::from_le_bytes(&<[u8; 32]>::try_from(&data[..32]).unwrap());
let xx = Scalar::from_le_bytes(&<[u8; 32]>::try_from(&data[32..64]).unwrap());
let yy = Scalar::from_le_bytes(&<[u8; 32]>::try_from(&data[64..]).unwrap());
ww.and_then(|w| {
xx.and_then(|x| yy.and_then(|y| CtOption::new(Self { w, x, y }, Choice::from(1u8))))
})
}
pub fn sign<B: AsRef<[u8]>>(&self, id: B) -> Option<Token> {
Token::new(self, id)
}
}