use curve25519_dalek::edwards::{CompressedEdwardsY, EdwardsPoint};
use curve25519_dalek::scalar::Scalar;
use sha2::{Digest, Sha256, Sha512};
use crate::lexical::to_hex;
pub fn sha256(data: &[u8]) -> [u8; 32] {
let mut out = [0u8; 32];
out.copy_from_slice(&Sha256::digest(data));
out
}
pub fn sha256_hex(data: &[u8]) -> String {
to_hex(&sha256(data))
}
pub fn key_id(public: &[u8; 32]) -> String {
let mut h = sha256_hex(public);
h.truncate(16);
h
}
fn strict_point(bytes: &[u8; 32]) -> Option<EdwardsPoint> {
let point = CompressedEdwardsY(*bytes).decompress()?;
if point.compress().to_bytes() != *bytes || point.is_small_order() {
return None;
}
Some(point)
}
pub fn verify_ed25519(public: &[u8; 32], message: &[u8], signature: &[u8; 64]) -> bool {
let mut r_bytes = [0u8; 32];
let mut s_bytes = [0u8; 32];
r_bytes.copy_from_slice(&signature[..32]);
s_bytes.copy_from_slice(&signature[32..]);
let s: Option<Scalar> = Scalar::from_canonical_bytes(s_bytes).into();
let Some(s) = s else { return false };
let Some(a) = strict_point(public) else { return false };
if strict_point(&r_bytes).is_none() {
return false;
}
let mut h = Sha512::new();
h.update(r_bytes);
h.update(public);
h.update(message);
let mut wide = [0u8; 64];
wide.copy_from_slice(&h.finalize());
let k = Scalar::from_bytes_mod_order_wide(&wide);
let r_check = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(-a), &s);
r_check.compress().to_bytes() == r_bytes
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn key_id_of_rates_key() {
let p =
crate::lexical::decode_hex_lower::<32>("843baeb22bfd0364fb1b7262b367fb3202e7886c69a070fecf8e343fedb1eabf")
.unwrap();
assert_eq!(key_id(&p), "d712b32a2cc5cb7c");
}
}