hash_based_signatures/signature/
stateless_merkle.rs1use crate::signature::q_indexed_signature::{QIndexedSignature, QIndexedSignatureScheme};
2use crate::signature::winternitz::d::D;
3use crate::signature::{HashType, SignatureScheme};
4use crate::utils::{hash, hmac, string_to_hash};
5use anyhow::Result;
6use data_encoding::HEXLOWER;
7use rand::Rng;
8use rand_chacha::rand_core::SeedableRng;
9use rand_chacha::ChaCha20Rng;
10use serde::{Deserialize, Serialize};
11use std::fmt::{Debug, Formatter};
12
13#[derive(Serialize, Deserialize)]
14pub struct StatelessMerklePrivateKey {
15 pub seed_hex: String,
16 pub width: usize,
17 pub depth: usize,
18 pub d: u64,
19 pub public_key: String,
21}
22
23pub struct StatelessMerkleSignatureScheme {
60 seed: HashType,
61 seed_prf_key: HashType,
62 path_prf_key: HashType,
63 root_signature: QIndexedSignatureScheme,
64 q: usize,
65 depth: usize,
66 d: D,
67}
68
69#[derive(PartialEq, Serialize, Deserialize)]
70pub struct StatelessMerkleSignature {
71 public_key_signatures: Vec<(HashType, QIndexedSignature)>,
72 message_signature: QIndexedSignature,
73}
74
75impl Debug for StatelessMerkleSignature {
76 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
77 let mut result = String::from("Stateless signature:\n");
78 for (message, signature) in &self.public_key_signatures {
79 result += &format!(
80 "- ({}, {})\n",
81 signature.proof.index,
82 HEXLOWER.encode(message)
83 );
84 }
85 result += &format!(
86 "- ({}, <hashed message>)\n",
87 self.message_signature.proof.index,
88 );
89 write!(f, "{}", result)
90 }
91}
92
93impl StatelessMerkleSignatureScheme {
94 pub fn new(seed: HashType, q: usize, depth: usize, d: D) -> Self {
104 let root_seed = hmac(&seed, &[0]);
106 let seed_prf_key = hmac(&seed, &[1]);
107 let path_prf_key = hmac(&seed, &[2]);
108 Self {
109 seed,
110 root_signature: QIndexedSignatureScheme::new(q, root_seed, d),
111 seed_prf_key,
112 path_prf_key,
113 q,
114 depth,
115 d,
116 }
117 }
118
119 pub fn from_private_key(key: &StatelessMerklePrivateKey) -> Result<Self> {
120 Ok(Self::new(
121 string_to_hash(&key.seed_hex),
122 key.width,
123 key.depth,
124 D::try_from(key.d)?,
125 ))
126 }
127
128 pub fn private_key(&self) -> StatelessMerklePrivateKey {
129 StatelessMerklePrivateKey {
130 seed_hex: HEXLOWER.encode(&self.seed),
131 public_key: HEXLOWER.encode(&self.public_key()),
132 width: self.q,
133 depth: self.depth,
134 d: self.d.d,
135 }
136 }
137
138 fn signature_scheme(&self, path: &[usize]) -> QIndexedSignatureScheme {
139 if path.len() == 0 {
140 self.root_signature.clone()
141 } else {
142 let path_bytes: Vec<u8> = path.iter().map(|x| x.to_be_bytes()).flatten().collect();
143 let seed = hmac(&self.seed_prf_key, &path_bytes);
144 QIndexedSignatureScheme::new(self.q, seed, self.d)
145 }
146 }
147}
148
149impl SignatureScheme<HashType, HashType, StatelessMerkleSignature>
150 for StatelessMerkleSignatureScheme
151{
152 fn public_key(&self) -> HashType {
153 self.root_signature.public_key()
154 }
155
156 fn sign(&mut self, message: HashType) -> StatelessMerkleSignature {
157 let mut rng = ChaCha20Rng::from_seed(hmac(&self.path_prf_key, &message));
159 let path: Vec<usize> = (0..self.depth).map(|_| rng.gen_range(0..self.q)).collect();
160
161 let mut public_key_signatures = Vec::with_capacity(self.depth);
162 let mut current_signing_scheme = self.root_signature.clone();
163 for (path_index, signature_index) in path.iter().enumerate() {
164 let next_signature_scheme = self.signature_scheme(&path[..path_index + 1]);
166 let one_time_signature =
167 current_signing_scheme.sign((*signature_index, next_signature_scheme.public_key()));
168
169 public_key_signatures.push((next_signature_scheme.public_key(), one_time_signature));
170 current_signing_scheme = next_signature_scheme;
171 }
172
173 let hashed_message = hash(&message);
177
178 let message_signature =
180 current_signing_scheme.sign((*path.last().unwrap(), hashed_message));
181
182 StatelessMerkleSignature {
183 public_key_signatures,
184 message_signature,
185 }
186 }
187
188 fn verify(pk: HashType, message: HashType, signature: &StatelessMerkleSignature) -> bool {
189 let mut current_public_key = pk;
190
191 for (public_key, one_time_signature) in &signature.public_key_signatures {
193 if !QIndexedSignatureScheme::verify(
194 current_public_key,
195 (one_time_signature.proof.index, *public_key),
196 one_time_signature,
197 ) {
198 return false;
199 }
200 current_public_key = *public_key;
201 }
202
203 QIndexedSignatureScheme::verify(
205 current_public_key,
206 (signature.message_signature.proof.index, hash(&message)),
207 &signature.message_signature,
208 )
209 }
210}
211
212#[cfg(test)]
213mod tests {
214 use crate::signature::stateless_merkle::StatelessMerkleSignatureScheme;
215 use crate::signature::winternitz::d::D;
216 use crate::signature::SignatureScheme;
217
218 fn get_signature_scheme() -> StatelessMerkleSignatureScheme {
219 let seed = [0u8; 32];
220 StatelessMerkleSignatureScheme::new(seed, 16, 5, D::new(255))
221 }
222
223 #[test]
224 fn test_correct_signature() {
225 let mut signature_scheme = get_signature_scheme();
226 let signature = signature_scheme.sign([1u8; 32]);
227 assert!(StatelessMerkleSignatureScheme::verify(
228 signature_scheme.public_key(),
229 [1u8; 32],
230 &signature
231 ))
232 }
233
234 #[test]
235 fn is_deterministic() {
236 let mut signature_scheme = get_signature_scheme();
237 let signature1 = signature_scheme.sign([1u8; 32]);
238 let signature2 = signature_scheme.sign([1u8; 32]);
239 assert_eq!(signature1, signature2)
240 }
241
242 #[test]
243 fn test_incorrect_signature() {
244 let mut signature_scheme = get_signature_scheme();
245 let signature = signature_scheme.sign([1u8; 32]);
246 assert!(!StatelessMerkleSignatureScheme::verify(
247 signature_scheme.public_key(),
248 [2u8; 32],
249 &signature
250 ))
251 }
252}