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
219#[allow(non_snake_case)]
221#[must_use]
222pub fn signValue(payload: &Value, key: &SigningKey) -> Signature {
223 sign_value(payload, key)
224}
225
226#[allow(non_snake_case)]
228#[must_use]
229pub fn verifySignedValue(payload: &Value, signature: &Signature, key: &VerifyingKey) -> bool {
230 verify_signed_value(payload, signature, key)
231}
232
233fn merge_hash_pair(left: Hash, right: Hash) -> Hash {
234 let mut bytes = left.0.to_vec();
235 bytes.extend_from_slice(&right.0);
236 hash_bytes_with_tag(HashTag::MerkleNode, &bytes)
237}
238
239#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
241pub struct AuthProof {
242 pub index: usize,
244 pub siblings: Vec<Hash>,
246 pub sibling_on_left: Vec<bool>,
248}
249
250#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
252pub struct AuthTree {
253 leaves: Vec<Hash>,
254 levels: Vec<Vec<Hash>>,
255}
256
257impl AuthTree {
258 #[must_use]
260 pub fn new(leaves: Vec<Hash>) -> Self {
261 if leaves.is_empty() {
262 return Self {
263 leaves,
264 levels: vec![vec![hash_bytes_with_tag(HashTag::MerkleLeaf, &[])]],
265 };
266 }
267 let mut levels = vec![leaves.clone()];
268 let mut level = leaves.clone();
269 while level.len() > 1 {
270 let mut next = Vec::with_capacity(level.len().div_ceil(2));
271 for chunk in level.chunks(2) {
272 let left = chunk[0];
273 let right = if chunk.len() == 2 { chunk[1] } else { chunk[0] };
274 next.push(merge_hash_pair(left, right));
275 }
276 levels.push(next.clone());
277 level = next;
278 }
279 Self { leaves, levels }
280 }
281
282 pub fn append_leaf(&mut self, leaf: Hash) {
284 if self.leaves.is_empty() {
285 *self = Self::new(vec![leaf]);
286 return;
287 }
288 self.leaves.push(leaf);
289 self.levels[0].push(leaf);
290 let mut idx = self.levels[0].len() - 1;
291 let mut level_idx = 0;
292 loop {
293 let level = &self.levels[level_idx];
295 let pair_start = idx & !1;
296 let left = level[pair_start];
297 let right = if pair_start + 1 < level.len() {
298 level[pair_start + 1]
299 } else {
300 left
301 };
302 let parent = merge_hash_pair(left, right);
303 let parent_idx = pair_start / 2;
304 if self.levels.len() == level_idx + 1 {
305 self.levels.push(Vec::new());
306 }
307 let next = &mut self.levels[level_idx + 1];
308 if parent_idx < next.len() {
309 next[parent_idx] = parent;
310 } else {
311 next.push(parent);
312 }
313 if parent_idx == 0 && next.len() == 1 {
314 break;
315 }
316 idx = parent_idx;
317 level_idx += 1;
318 }
319 }
320
321 #[must_use]
323 pub fn root(&self) -> Hash {
324 self.levels
325 .last()
326 .and_then(|level| level.first().copied())
327 .unwrap_or_else(|| hash_bytes_with_tag(HashTag::MerkleLeaf, &[]))
328 }
329
330 #[must_use]
332 pub fn prove(&self, index: usize) -> Option<AuthProof> {
333 if index >= self.leaves.len() {
334 return None;
335 }
336 let mut idx = index;
337 let mut siblings = Vec::new();
338 let mut sibling_on_left = Vec::new();
339 for level in &self.levels {
340 if level.len() <= 1 {
341 break;
342 }
343 let pair_index = idx ^ 1;
344 let sibling = if pair_index < level.len() {
345 level[pair_index]
346 } else {
347 level[idx]
348 };
349 siblings.push(sibling);
350 sibling_on_left.push(pair_index < idx);
351 idx /= 2;
352 }
353 Some(AuthProof {
354 index,
355 siblings,
356 sibling_on_left,
357 })
358 }
359
360 #[must_use]
362 pub fn verify(root: Hash, leaf: Hash, proof: &AuthProof) -> bool {
363 if proof.siblings.len() != proof.sibling_on_left.len() {
364 return false;
365 }
366 let mut current = leaf;
367 let mut index = proof.index;
368 for (sibling, on_left) in proof.siblings.iter().zip(proof.sibling_on_left.iter()) {
369 let expected_on_left = index % 2 == 1;
370 if *on_left != expected_on_left {
371 return false;
372 }
373 current = if *on_left {
374 merge_hash_pair(*sibling, current)
375 } else {
376 merge_hash_pair(current, *sibling)
377 };
378 index /= 2;
379 }
380 current == root
381 }
382}
383
384#[cfg(test)]
385mod tests {
386 use super::*;
387
388 #[test]
389 fn signature_roundtrip() {
390 let ep = Endpoint {
391 sid: 9,
392 role: "Alice".to_string(),
393 };
394 let sk = signing_key_for_endpoint(&ep);
395 let vk = verifying_key_for_endpoint(&ep);
396 let payload = Value::Nat(42);
397 let sig = sign_value(&payload, &sk);
398 assert!(verify_signed_value(&payload, &sig, &vk));
399 assert!(!verify_signed_value(&Value::Nat(7), &sig, &vk));
400 }
401
402 #[test]
403 fn auth_tree_proof_roundtrip() {
404 let leaves = vec![
405 hash_bytes_with_tag(HashTag::MerkleLeaf, b"a"),
406 hash_bytes_with_tag(HashTag::MerkleLeaf, b"b"),
407 hash_bytes_with_tag(HashTag::MerkleLeaf, b"c"),
408 ];
409 let tree = AuthTree::new(leaves.clone());
410 let proof = tree.prove(1).expect("proof for valid index");
411 assert!(AuthTree::verify(tree.root(), leaves[1], &proof));
412 }
413
414 #[test]
415 fn auth_tree_incremental_append_matches_rebuild() {
416 let leaves = vec![
417 hash_bytes_with_tag(HashTag::MerkleLeaf, b"a"),
418 hash_bytes_with_tag(HashTag::MerkleLeaf, b"b"),
419 hash_bytes_with_tag(HashTag::MerkleLeaf, b"c"),
420 hash_bytes_with_tag(HashTag::MerkleLeaf, b"d"),
421 hash_bytes_with_tag(HashTag::MerkleLeaf, b"e"),
422 ];
423 let mut incremental = AuthTree::new(vec![leaves[0]]);
424 for leaf in leaves.iter().skip(1) {
425 incremental.append_leaf(*leaf);
426 }
427 let rebuilt = AuthTree::new(leaves);
428 assert_eq!(incremental.root(), rebuilt.root());
429 }
430}