use crate::hazmat::dstu4145::curve257::{self, Point};
use crate::hazmat::dstu4145::gf2m257::FieldElement;
use crate::hazmat::dstu4145::scalar257::Scalar;
use crate::hazmat::dstu4145::signature257;
use crate::hazmat::kupyna::Kupyna256;
use crate::hazmat::kupyna_kmac::Kupyna384Kmac;
use zeroize::Zeroize;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Signature {
r: [u8; 33],
s: [u8; 33],
}
impl Signature {
#[must_use]
pub fn to_bytes(&self) -> [u8; 66] {
let mut out = [0u8; 66];
out[..33].copy_from_slice(&self.r);
out[33..].copy_from_slice(&self.s);
out
}
#[must_use]
pub fn from_bytes(bytes: &[u8; 66]) -> Self {
let mut r = [0u8; 33];
let mut s = [0u8; 33];
r.copy_from_slice(&bytes[..33]);
s.copy_from_slice(&bytes[33..]);
Signature { r, s }
}
}
pub struct SigningKey(Scalar);
impl Drop for SigningKey {
fn drop(&mut self) {
self.0.zeroize();
}
}
#[derive(Clone, Copy)]
pub struct VerifyingKey(Point);
impl SigningKey {
#[must_use]
pub fn from_bytes(d: &[u8; 33]) -> Option<Self> {
let n = curve257::order();
if d.iter().all(|&b| b == 0) || d >= &n {
return None;
}
Some(SigningKey(Scalar::from_be_bytes(d)))
}
#[cfg(any(feature = "std", feature = "getrandom"))]
pub fn generate() -> Result<Self, crate::randombytes::RandomError> {
loop {
let mut candidate = [0u8; 33];
crate::randombytes::randombytes_buf(&mut candidate)?;
candidate[0] = 0;
candidate[1] &= 0x01;
let scalar = Scalar::from_candidate_bytes(&candidate);
candidate.zeroize();
if let Some(scalar) = scalar {
return Ok(SigningKey(scalar));
}
}
}
#[must_use]
pub fn to_bytes(&self) -> [u8; 33] {
self.0.to_be_bytes()
}
#[must_use]
pub fn verifying_key(&self) -> VerifyingKey {
let g = Point::generator();
let q = g.scalar_multiply(&self.0.to_be_bytes()).negate();
VerifyingKey(q)
}
#[must_use]
pub fn sign(&self, message: &[u8]) -> Signature {
self.sign_digest(&Kupyna256::digest(message))
}
#[must_use]
pub fn sign_digest(&self, digest: &[u8; 32]) -> Signature {
let g = Point::generator();
let mut counter: u8 = 0;
loop {
let e = derive_nonce(self.0, digest, counter);
if let Some((r, s)) = signature257::sign(digest, self.0, e, g) {
return Signature { r, s };
}
counter = counter.wrapping_add(1);
}
}
}
impl VerifyingKey {
#[must_use]
pub fn to_uncompressed_bytes(&self) -> [u8; 66] {
let mut out = [0u8; 66];
match self.0 {
Point::Affine(x, y) => {
out[..33].copy_from_slice(&x.to_be_bytes());
out[33..].copy_from_slice(&y.to_be_bytes());
}
Point::Infinity => {} }
out
}
#[must_use]
pub fn from_uncompressed_bytes(bytes: &[u8; 66]) -> Self {
let x = FieldElement::from_be_bytes(&bytes[..33]);
let y = FieldElement::from_be_bytes(&bytes[33..]);
VerifyingKey(Point::Affine(x, y))
}
#[must_use]
pub fn verify(&self, message: &[u8], sig: &Signature) -> bool {
self.verify_digest(&Kupyna256::digest(message), sig)
}
#[must_use]
pub fn verify_digest(&self, digest: &[u8; 32], sig: &Signature) -> bool {
let g = Point::generator();
signature257::verify(digest, &sig.r, &sig.s, self.0, g)
}
}
fn derive_nonce(d: Scalar, hash: &[u8; 32], counter: u8) -> Scalar {
let mut key = [0u8; 48];
key[15..].copy_from_slice(&d.to_be_bytes());
let mut message = [0u8; 33];
message[..32].copy_from_slice(hash);
message[32] = counter;
let Ok(mac) = Kupyna384Kmac::mac(&key, &message) else {
unreachable!("key is always exactly 48 bytes, Kupyna384Kmac's required length")
};
key.zeroize();
Scalar::reduce_wide_bytes(&mac)
}