use crate::signature::q_indexed_signature::{QIndexedSignature, QIndexedSignatureScheme};
use crate::signature::winternitz::d::D;
use crate::signature::{HashType, SignatureScheme};
use crate::utils::{hash, hmac, string_to_hash};
use anyhow::Result;
use data_encoding::HEXLOWER;
use rand::Rng;
use rand_chacha::rand_core::SeedableRng;
use rand_chacha::ChaCha20Rng;
use serde::{Deserialize, Serialize};
use std::fmt::{Debug, Formatter};
#[derive(Serialize, Deserialize)]
pub struct StatelessMerklePrivateKey {
pub seed_hex: String,
pub width: usize,
pub depth: usize,
pub d: u64,
pub public_key: String,
}
pub struct StatelessMerkleSignatureScheme {
seed: HashType,
seed_prf_key: HashType,
path_prf_key: HashType,
root_signature: QIndexedSignatureScheme,
q: usize,
depth: usize,
d: D,
}
#[derive(PartialEq, Serialize, Deserialize)]
pub struct StatelessMerkleSignature {
public_key_signatures: Vec<(HashType, QIndexedSignature)>,
message_signature: QIndexedSignature,
}
impl Debug for StatelessMerkleSignature {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut result = String::from("Stateless signature:\n");
for (message, signature) in &self.public_key_signatures {
result += &format!(
"- ({}, {})\n",
signature.proof.index,
HEXLOWER.encode(message)
);
}
result += &format!(
"- ({}, <hashed message>)\n",
self.message_signature.proof.index,
);
write!(f, "{}", result)
}
}
impl StatelessMerkleSignatureScheme {
pub fn new(seed: HashType, q: usize, depth: usize, d: D) -> Self {
let root_seed = hmac(&seed, &[0]);
let seed_prf_key = hmac(&seed, &[1]);
let path_prf_key = hmac(&seed, &[2]);
Self {
seed,
root_signature: QIndexedSignatureScheme::new(q, root_seed, d),
seed_prf_key,
path_prf_key,
q,
depth,
d,
}
}
pub fn from_private_key(key: &StatelessMerklePrivateKey) -> Result<Self> {
Ok(Self::new(
string_to_hash(&key.seed_hex),
key.width,
key.depth,
D::try_from(key.d)?,
))
}
pub fn private_key(&self) -> StatelessMerklePrivateKey {
StatelessMerklePrivateKey {
seed_hex: HEXLOWER.encode(&self.seed),
public_key: HEXLOWER.encode(&self.public_key()),
width: self.q,
depth: self.depth,
d: self.d.d,
}
}
fn signature_scheme(&self, path: &[usize]) -> QIndexedSignatureScheme {
if path.len() == 0 {
self.root_signature.clone()
} else {
let path_bytes: Vec<u8> = path.iter().map(|x| x.to_be_bytes()).flatten().collect();
let seed = hmac(&self.seed_prf_key, &path_bytes);
QIndexedSignatureScheme::new(self.q, seed, self.d)
}
}
}
impl SignatureScheme<HashType, HashType, StatelessMerkleSignature>
for StatelessMerkleSignatureScheme
{
fn public_key(&self) -> HashType {
self.root_signature.public_key()
}
fn sign(&mut self, message: HashType) -> StatelessMerkleSignature {
let mut rng = ChaCha20Rng::from_seed(hmac(&self.path_prf_key, &message));
let path: Vec<usize> = (0..self.depth).map(|_| rng.gen_range(0..self.q)).collect();
let mut public_key_signatures = Vec::with_capacity(self.depth);
let mut current_signing_scheme = self.root_signature.clone();
for (path_index, signature_index) in path.iter().enumerate() {
let next_signature_scheme = self.signature_scheme(&path[..path_index + 1]);
let one_time_signature =
current_signing_scheme.sign((*signature_index, next_signature_scheme.public_key()));
public_key_signatures.push((next_signature_scheme.public_key(), one_time_signature));
current_signing_scheme = next_signature_scheme;
}
let hashed_message = hash(&message);
let message_signature =
current_signing_scheme.sign((*path.last().unwrap(), hashed_message));
StatelessMerkleSignature {
public_key_signatures,
message_signature,
}
}
fn verify(pk: HashType, message: HashType, signature: &StatelessMerkleSignature) -> bool {
let mut current_public_key = pk;
for (public_key, one_time_signature) in &signature.public_key_signatures {
if !QIndexedSignatureScheme::verify(
current_public_key,
(one_time_signature.proof.index, *public_key),
one_time_signature,
) {
return false;
}
current_public_key = *public_key;
}
QIndexedSignatureScheme::verify(
current_public_key,
(signature.message_signature.proof.index, hash(&message)),
&signature.message_signature,
)
}
}
#[cfg(test)]
mod tests {
use crate::signature::stateless_merkle::StatelessMerkleSignatureScheme;
use crate::signature::winternitz::d::D;
use crate::signature::SignatureScheme;
fn get_signature_scheme() -> StatelessMerkleSignatureScheme {
let seed = [0u8; 32];
StatelessMerkleSignatureScheme::new(seed, 16, 5, D::new(255))
}
#[test]
fn test_correct_signature() {
let mut signature_scheme = get_signature_scheme();
let signature = signature_scheme.sign([1u8; 32]);
assert!(StatelessMerkleSignatureScheme::verify(
signature_scheme.public_key(),
[1u8; 32],
&signature
))
}
#[test]
fn is_deterministic() {
let mut signature_scheme = get_signature_scheme();
let signature1 = signature_scheme.sign([1u8; 32]);
let signature2 = signature_scheme.sign([1u8; 32]);
assert_eq!(signature1, signature2)
}
#[test]
fn test_incorrect_signature() {
let mut signature_scheme = get_signature_scheme();
let signature = signature_scheme.sign([1u8; 32]);
assert!(!StatelessMerkleSignatureScheme::verify(
signature_scheme.public_key(),
[2u8; 32],
&signature
))
}
}