use super::{constants::*, errors::*, public::*};
use crate::common::*;
use core::fmt::Debug;
use curve25519_dalek::{
constants,
scalar::{clamp_integer, Scalar},
};
use rand::{CryptoRng, Rng};
use sha2::{digest::Digest, Sha512};
use subtle::{Choice, ConstantTimeEq};
use zeroize::Zeroize;
pub struct SecretKey(pub(crate) [u8; SECRET_KEY_LENGTH]);
impl ConstantTimeEq for SecretKey {
fn ct_eq(&self, other: &Self) -> Choice { self.0.ct_eq(&other.0) }
}
impl Serial for SecretKey {
#[inline]
fn serial<B: Buffer>(&self, x: &mut B) {
x.write_all(&self.0)
.expect("Writing to buffer should succeed.")
}
}
impl Deserial for SecretKey {
#[inline]
fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
let mut buf = [0u8; SECRET_KEY_LENGTH];
source.read_exact(&mut buf)?;
Ok(SecretKey(buf))
}
}
impl Debug for SecretKey {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
write!(f, "SecretKey: {:?}", &self.0[..])
}
}
impl Drop for SecretKey {
fn drop(&mut self) { self.0.zeroize(); }
}
impl AsRef<[u8]> for SecretKey {
fn as_ref(&self) -> &[u8] { self.as_bytes() }
}
impl SecretKey {
#[inline]
pub fn to_bytes(&self) -> Box<[u8]> { Box::new(self.0) }
#[inline]
pub fn as_bytes(&self) -> &'_ [u8; SECRET_KEY_LENGTH] { &self.0 }
#[inline]
pub fn from_bytes(bytes: &[u8]) -> Result<SecretKey, ProofError> {
if bytes.len() != SECRET_KEY_LENGTH {
return Err(ProofError(InternalError::BytesLength {
name: "SecretKey",
length: SECRET_KEY_LENGTH,
}));
}
let mut bits: [u8; 32] = [0u8; 32];
bits.copy_from_slice(&bytes[..32]);
Ok(SecretKey(bits))
}
pub fn prove(&self, public_key: &PublicKey, message: &[u8]) -> Proof {
ExpandedSecretKey::from(self).prove(public_key, message)
}
pub fn generate<T>(csprng: &mut T) -> SecretKey
where
T: CryptoRng + Rng, {
let mut sk: SecretKey = SecretKey([0u8; 32]);
csprng.fill_bytes(&mut sk.0);
sk
}
}
pub(crate) struct ExpandedSecretKey {
pub(crate) key: Scalar,
pub(crate) nonce: [u8; 32],
}
impl Drop for ExpandedSecretKey {
fn drop(&mut self) {
self.key.zeroize();
self.nonce.zeroize();
}
}
impl From<&SecretKey> for ExpandedSecretKey {
fn from(secret_key: &SecretKey) -> ExpandedSecretKey {
let mut h: Sha512 = Sha512::new();
let mut hash: [u8; 64] = [0u8; 64];
let mut lower: [u8; 32] = [0u8; 32];
let mut upper: [u8; 32] = [0u8; 32];
h.update(secret_key.as_bytes());
hash.copy_from_slice(h.finalize().as_slice());
lower.copy_from_slice(&hash[00..32]);
upper.copy_from_slice(&hash[32..64]);
ExpandedSecretKey {
key: Scalar::from_bytes_mod_order(clamp_integer(lower)),
nonce: upper,
}
}
}
use super::proof::*;
impl ExpandedSecretKey {
pub fn prove(&self, public_key: &PublicKey, alpha: &[u8]) -> Proof {
let x = self.key;
let h = public_key
.hash_to_curve(alpha)
.expect("Failure should not happen for non-maliciously crafted input.");
let h_string = h.compress().to_bytes();
let k = self.nonce_generation(&h_string);
let gamma = x * h;
let c = hash_points(&[
h.compress(),
gamma.compress(),
(k * constants::ED25519_BASEPOINT_POINT).compress(), (k * h).compress(), ]);
let k_plus_cx = k + c * x;
Proof(gamma, c, k_plus_cx)
}
fn nonce_generation(&self, h_string: &[u8]) -> Scalar {
let digest = Sha512::new()
.chain_update(self.nonce)
.chain_update(h_string)
.finalize();
Scalar::from_bytes_mod_order_wide(&digest.into())
}
}