use crate::{PROOF_LENGTH, Proof, PublicKey, challenge, sha512};
use curve25519_dalek::{
Scalar, constants::ED25519_BASEPOINT_POINT as B, edwards::CompressedEdwardsY,
scalar::clamp_integer,
};
#[derive(Clone, Copy)]
pub struct SecretKey(pub [u8; 32]);
impl SecretKey {
fn expand(&self) -> (Scalar, [u8; 32]) {
let h = sha512::hashv(&[&self.0]);
let x = Scalar::from_bytes_mod_order(clamp_integer(h[..32].try_into().unwrap()));
(x, h[32..].try_into().unwrap())
}
pub fn public_key(&self) -> PublicKey {
PublicKey((self.expand().0 * B).compress().0)
}
pub fn prove(&self, alpha: &[u8]) -> Proof {
let (x, nonce_key) = self.expand();
let y = (x * B).compress().0;
let h_bytes = crate::encode_to_curve(&y, alpha).expect("2^-256");
let h = CompressedEdwardsY(h_bytes).decompress().unwrap();
let gamma = x * h;
let k = Scalar::from_bytes_mod_order_wide(&sha512::hashv(&[&nonce_key, &h_bytes]));
let u = (k * B).compress().0;
let v = (k * h).compress().0;
let gamma_bytes = gamma.compress().0;
let c = challenge(&y, &h_bytes, &gamma_bytes, &u, &v);
let mut c_wide = [0u8; 32];
c_wide[..16].copy_from_slice(&c);
let s = k + Scalar::from_bytes_mod_order(c_wide) * x;
let mut pi = [0u8; PROOF_LENGTH];
pi[..32].copy_from_slice(&gamma_bytes);
pi[32..48].copy_from_slice(&c);
pi[48..].copy_from_slice(&s.to_bytes());
Proof(pi)
}
}