1use std::hash::{Hash as StdHash, Hasher};
7
8use serde::{Deserialize, Serialize};
9
10use crate::coroutine::Value;
11use crate::instr::Endpoint;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
15pub struct Hash(pub [u8; 32]);
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
19pub enum HashTag {
20 Value,
22 SignedValue,
24 MerkleLeaf,
26 MerkleNode,
28 Commitment,
30 Nullifier,
32 SigningKey,
34}
35
36impl HashTag {
37 fn domain_byte(self) -> u8 {
38 match self {
39 Self::Value => 0x01,
40 Self::SignedValue => 0x02,
41 Self::MerkleLeaf => 0x03,
42 Self::MerkleNode => 0x04,
43 Self::Commitment => 0x05,
44 Self::Nullifier => 0x06,
45 Self::SigningKey => 0x07,
46 }
47 }
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
52pub struct SigningKey(pub [u8; 32]);
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
56pub struct VerifyingKey(pub [u8; 32]);
57
58#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
60pub struct Signature {
61 pub signer: VerifyingKey,
63 pub digest: Hash,
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
69pub struct Commitment(pub Hash);
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
73pub struct Nullifier(pub Hash);
74
75pub trait VerificationModel {
77 type Hash;
79 type SigningKey;
81 type VerifyingKey;
83 type Signature;
85 type Commitment;
87 type Nullifier;
89
90 fn hash(tag: HashTag, bytes: &[u8]) -> Self::Hash;
92 fn deriving(signing: &Self::SigningKey) -> Self::VerifyingKey;
94 fn sign_value(payload: &Value, key: &Self::SigningKey) -> Self::Signature;
96 fn verify_signed_value(
98 payload: &Value,
99 signature: &Self::Signature,
100 key: &Self::VerifyingKey,
101 ) -> bool;
102 fn commitment(payload: &Value) -> Self::Commitment;
104 fn nullifier(payload: &Value) -> Self::Nullifier;
106}
107
108#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
110pub struct DefaultVerificationModel;
111
112fn hash_bytes_with_tag(tag: HashTag, bytes: &[u8]) -> Hash {
113 let mut out = [0_u8; 32];
116 for block in 0_u64..4 {
117 let mut hasher = std::collections::hash_map::DefaultHasher::new();
118 tag.domain_byte().hash(&mut hasher);
119 block.hash(&mut hasher);
120 bytes.hash(&mut hasher);
121 let digest = hasher.finish().to_le_bytes();
122 let Ok(block_usize) = usize::try_from(block) else {
123 return Hash(out);
124 };
125 let start = block_usize * 8;
126 out[start..start + 8].copy_from_slice(&digest);
127 }
128 Hash(out)
129}
130
131fn encode_value(value: &Value) -> Vec<u8> {
132 serde_json::to_vec(value).unwrap_or_else(|_| format!("{value:?}").into_bytes())
133}
134
135impl VerificationModel for DefaultVerificationModel {
136 type Hash = Hash;
137 type SigningKey = SigningKey;
138 type VerifyingKey = VerifyingKey;
139 type Signature = Signature;
140 type Commitment = Commitment;
141 type Nullifier = Nullifier;
142
143 fn hash(tag: HashTag, bytes: &[u8]) -> Self::Hash {
144 hash_bytes_with_tag(tag, bytes)
145 }
146
147 fn deriving(signing: &Self::SigningKey) -> Self::VerifyingKey {
148 let digest = hash_bytes_with_tag(HashTag::SigningKey, &signing.0);
149 VerifyingKey(digest.0)
150 }
151
152 fn sign_value(payload: &Value, key: &Self::SigningKey) -> Self::Signature {
153 crate::verification::sign_value(payload, key)
154 }
155
156 fn verify_signed_value(
157 payload: &Value,
158 signature: &Self::Signature,
159 key: &Self::VerifyingKey,
160 ) -> bool {
161 verify_signed_value(payload, signature, key)
162 }
163
164 fn commitment(payload: &Value) -> Self::Commitment {
165 Commitment(hash_bytes_with_tag(
166 HashTag::Commitment,
167 &encode_value(payload),
168 ))
169 }
170
171 fn nullifier(payload: &Value) -> Self::Nullifier {
172 Nullifier(hash_bytes_with_tag(
173 HashTag::Nullifier,
174 &encode_value(payload),
175 ))
176 }
177}
178
179#[must_use]
181pub fn signing_key_for_endpoint(endpoint: &Endpoint) -> SigningKey {
182 let mut bytes = endpoint.sid.to_le_bytes().to_vec();
183 bytes.extend_from_slice(endpoint.role.as_bytes());
184 let digest = hash_bytes_with_tag(HashTag::SigningKey, &bytes);
185 SigningKey(digest.0)
186}
187
188#[must_use]
190pub fn verifying_key_for_endpoint(endpoint: &Endpoint) -> VerifyingKey {
191 DefaultVerificationModel::deriving(&signing_key_for_endpoint(endpoint))
192}
193
194#[must_use]
196pub fn sign_value(payload: &Value, key: &SigningKey) -> Signature {
197 let verifying = DefaultVerificationModel::deriving(key);
198 let mut bytes = verifying.0.to_vec();
199 bytes.extend_from_slice(&encode_value(payload));
200 let digest = hash_bytes_with_tag(HashTag::SignedValue, &bytes);
201 Signature {
202 signer: verifying,
203 digest,
204 }
205}
206
207#[must_use]
209pub fn verify_signed_value(payload: &Value, signature: &Signature, key: &VerifyingKey) -> bool {
210 if signature.signer != *key {
211 return false;
212 }
213 let mut bytes = key.0.to_vec();
214 bytes.extend_from_slice(&encode_value(payload));
215 let expected = hash_bytes_with_tag(HashTag::SignedValue, &bytes);
216 expected == signature.digest
217}
218
219fn merge_hash_pair(left: Hash, right: Hash) -> Hash {
220 let mut bytes = left.0.to_vec();
221 bytes.extend_from_slice(&right.0);
222 hash_bytes_with_tag(HashTag::MerkleNode, &bytes)
223}
224
225#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
227pub struct AuthProof {
228 pub index: usize,
230 pub siblings: Vec<Hash>,
232 pub sibling_on_left: Vec<bool>,
234}
235
236#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
238pub struct AuthTree {
239 leaves: Vec<Hash>,
240 levels: Vec<Vec<Hash>>,
241}
242
243impl AuthTree {
244 #[must_use]
246 pub fn new(leaves: Vec<Hash>) -> Self {
247 if leaves.is_empty() {
248 return Self {
249 leaves,
250 levels: vec![vec![hash_bytes_with_tag(HashTag::MerkleLeaf, &[])]],
251 };
252 }
253 let mut levels = vec![leaves.clone()];
254 let mut level = leaves.clone();
255 while level.len() > 1 {
256 let mut next = Vec::with_capacity(level.len().div_ceil(2));
257 for chunk in level.chunks(2) {
258 let left = chunk[0];
259 let right = if chunk.len() == 2 { chunk[1] } else { chunk[0] };
260 next.push(merge_hash_pair(left, right));
261 }
262 levels.push(next.clone());
263 level = next;
264 }
265 Self { leaves, levels }
266 }
267
268 pub fn append_leaf(&mut self, leaf: Hash) {
270 if self.leaves.is_empty() {
271 *self = Self::new(vec![leaf]);
272 return;
273 }
274 self.leaves.push(leaf);
275 self.levels[0].push(leaf);
276 let mut idx = self.levels[0].len() - 1;
277 let mut level_idx = 0;
278 loop {
279 let level = &self.levels[level_idx];
281 let pair_start = idx & !1;
282 let left = level[pair_start];
283 let right = if pair_start + 1 < level.len() {
284 level[pair_start + 1]
285 } else {
286 left
287 };
288 let parent = merge_hash_pair(left, right);
289 let parent_idx = pair_start / 2;
290 if self.levels.len() == level_idx + 1 {
291 self.levels.push(Vec::new());
292 }
293 let next = &mut self.levels[level_idx + 1];
294 if parent_idx < next.len() {
295 next[parent_idx] = parent;
296 } else {
297 next.push(parent);
298 }
299 if parent_idx == 0 && next.len() == 1 {
300 break;
301 }
302 idx = parent_idx;
303 level_idx += 1;
304 }
305 }
306
307 #[must_use]
309 pub fn root(&self) -> Hash {
310 self.levels
311 .last()
312 .and_then(|level| level.first().copied())
313 .unwrap_or_else(|| hash_bytes_with_tag(HashTag::MerkleLeaf, &[]))
314 }
315
316 #[must_use]
318 pub fn prove(&self, index: usize) -> Option<AuthProof> {
319 if index >= self.leaves.len() {
320 return None;
321 }
322 let mut idx = index;
323 let mut siblings = Vec::new();
324 let mut sibling_on_left = Vec::new();
325 for level in &self.levels {
326 if level.len() <= 1 {
327 break;
328 }
329 let pair_index = idx ^ 1;
330 let sibling = if pair_index < level.len() {
331 level[pair_index]
332 } else {
333 level[idx]
334 };
335 siblings.push(sibling);
336 sibling_on_left.push(pair_index < idx);
337 idx /= 2;
338 }
339 Some(AuthProof {
340 index,
341 siblings,
342 sibling_on_left,
343 })
344 }
345
346 #[must_use]
348 pub fn verify(root: Hash, leaf: Hash, proof: &AuthProof) -> bool {
349 if proof.siblings.len() != proof.sibling_on_left.len() {
350 return false;
351 }
352 let mut current = leaf;
353 let mut index = proof.index;
354 for (sibling, on_left) in proof.siblings.iter().zip(proof.sibling_on_left.iter()) {
355 let expected_on_left = index % 2 == 1;
356 if *on_left != expected_on_left {
357 return false;
358 }
359 current = if *on_left {
360 merge_hash_pair(*sibling, current)
361 } else {
362 merge_hash_pair(current, *sibling)
363 };
364 index /= 2;
365 }
366 current == root
367 }
368}
369
370#[cfg(test)]
371mod tests {
372 use super::*;
373
374 #[test]
375 fn signature_roundtrip() {
376 let ep = Endpoint {
377 sid: 9,
378 role: "Alice".to_string(),
379 };
380 let sk = signing_key_for_endpoint(&ep);
381 let vk = verifying_key_for_endpoint(&ep);
382 let payload = Value::Nat(42);
383 let sig = sign_value(&payload, &sk);
384 assert!(verify_signed_value(&payload, &sig, &vk));
385 assert!(!verify_signed_value(&Value::Nat(7), &sig, &vk));
386 }
387
388 #[test]
389 fn auth_tree_proof_roundtrip() {
390 let leaves = vec![
391 hash_bytes_with_tag(HashTag::MerkleLeaf, b"a"),
392 hash_bytes_with_tag(HashTag::MerkleLeaf, b"b"),
393 hash_bytes_with_tag(HashTag::MerkleLeaf, b"c"),
394 ];
395 let tree = AuthTree::new(leaves.clone());
396 let proof = tree.prove(1).expect("proof for valid index");
397 assert!(AuthTree::verify(tree.root(), leaves[1], &proof));
398 }
399
400 #[test]
401 fn auth_tree_incremental_append_matches_rebuild() {
402 let leaves = vec![
403 hash_bytes_with_tag(HashTag::MerkleLeaf, b"a"),
404 hash_bytes_with_tag(HashTag::MerkleLeaf, b"b"),
405 hash_bytes_with_tag(HashTag::MerkleLeaf, b"c"),
406 hash_bytes_with_tag(HashTag::MerkleLeaf, b"d"),
407 hash_bytes_with_tag(HashTag::MerkleLeaf, b"e"),
408 ];
409 let mut incremental = AuthTree::new(vec![leaves[0]]);
410 for leaf in leaves.iter().skip(1) {
411 incremental.append_leaf(*leaf);
412 }
413 let rebuilt = AuthTree::new(leaves);
414 assert_eq!(incremental.root(), rebuilt.root());
415 }
416}