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 start = usize::try_from(block).expect("u64 block index fits in usize") * 8;
123 out[start..start + 8].copy_from_slice(&digest);
124 }
125 Hash(out)
126}
127
128fn encode_value(value: &Value) -> Vec<u8> {
129 serde_json::to_vec(value).unwrap_or_else(|_| format!("{value:?}").into_bytes())
130}
131
132impl VerificationModel for DefaultVerificationModel {
133 type Hash = Hash;
134 type SigningKey = SigningKey;
135 type VerifyingKey = VerifyingKey;
136 type Signature = Signature;
137 type Commitment = Commitment;
138 type Nullifier = Nullifier;
139
140 fn hash(tag: HashTag, bytes: &[u8]) -> Self::Hash {
141 hash_bytes_with_tag(tag, bytes)
142 }
143
144 fn deriving(signing: &Self::SigningKey) -> Self::VerifyingKey {
145 let digest = hash_bytes_with_tag(HashTag::SigningKey, &signing.0);
146 VerifyingKey(digest.0)
147 }
148
149 fn sign_value(payload: &Value, key: &Self::SigningKey) -> Self::Signature {
150 crate::verification::sign_value(payload, key)
151 }
152
153 fn verify_signed_value(
154 payload: &Value,
155 signature: &Self::Signature,
156 key: &Self::VerifyingKey,
157 ) -> bool {
158 verify_signed_value(payload, signature, key)
159 }
160
161 fn commitment(payload: &Value) -> Self::Commitment {
162 Commitment(hash_bytes_with_tag(
163 HashTag::Commitment,
164 &encode_value(payload),
165 ))
166 }
167
168 fn nullifier(payload: &Value) -> Self::Nullifier {
169 Nullifier(hash_bytes_with_tag(
170 HashTag::Nullifier,
171 &encode_value(payload),
172 ))
173 }
174}
175
176#[must_use]
178pub fn signing_key_for_endpoint(endpoint: &Endpoint) -> SigningKey {
179 let mut bytes = endpoint.sid.to_le_bytes().to_vec();
180 bytes.extend_from_slice(endpoint.role.as_bytes());
181 let digest = hash_bytes_with_tag(HashTag::SigningKey, &bytes);
182 SigningKey(digest.0)
183}
184
185#[must_use]
187pub fn verifying_key_for_endpoint(endpoint: &Endpoint) -> VerifyingKey {
188 DefaultVerificationModel::deriving(&signing_key_for_endpoint(endpoint))
189}
190
191#[must_use]
193pub fn sign_value(payload: &Value, key: &SigningKey) -> Signature {
194 let verifying = DefaultVerificationModel::deriving(key);
195 let mut bytes = verifying.0.to_vec();
196 bytes.extend_from_slice(&encode_value(payload));
197 let digest = hash_bytes_with_tag(HashTag::SignedValue, &bytes);
198 Signature {
199 signer: verifying,
200 digest,
201 }
202}
203
204#[must_use]
206pub fn verify_signed_value(payload: &Value, signature: &Signature, key: &VerifyingKey) -> bool {
207 if signature.signer != *key {
208 return false;
209 }
210 let mut bytes = key.0.to_vec();
211 bytes.extend_from_slice(&encode_value(payload));
212 let expected = hash_bytes_with_tag(HashTag::SignedValue, &bytes);
213 expected == signature.digest
214}
215
216#[allow(non_snake_case)]
218#[must_use]
219pub fn signValue(payload: &Value, key: &SigningKey) -> Signature {
220 sign_value(payload, key)
221}
222
223#[allow(non_snake_case)]
225#[must_use]
226pub fn verifySignedValue(payload: &Value, signature: &Signature, key: &VerifyingKey) -> bool {
227 verify_signed_value(payload, signature, key)
228}
229
230fn merge_hash_pair(left: Hash, right: Hash) -> Hash {
231 let mut bytes = left.0.to_vec();
232 bytes.extend_from_slice(&right.0);
233 hash_bytes_with_tag(HashTag::MerkleNode, &bytes)
234}
235
236#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
238pub struct AuthProof {
239 pub index: usize,
241 pub siblings: Vec<Hash>,
243 pub sibling_on_left: Vec<bool>,
245}
246
247#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
249pub struct AuthTree {
250 leaves: Vec<Hash>,
251 levels: Vec<Vec<Hash>>,
252}
253
254impl AuthTree {
255 #[must_use]
257 pub fn new(leaves: Vec<Hash>) -> Self {
258 if leaves.is_empty() {
259 return Self {
260 leaves,
261 levels: vec![vec![hash_bytes_with_tag(HashTag::MerkleLeaf, &[])]],
262 };
263 }
264 let mut levels = vec![leaves.clone()];
265 let mut level = leaves.clone();
266 while level.len() > 1 {
267 let mut next = Vec::with_capacity(level.len().div_ceil(2));
268 for chunk in level.chunks(2) {
269 let left = chunk[0];
270 let right = if chunk.len() == 2 { chunk[1] } else { chunk[0] };
271 next.push(merge_hash_pair(left, right));
272 }
273 levels.push(next.clone());
274 level = next;
275 }
276 Self { leaves, levels }
277 }
278
279 pub fn append_leaf(&mut self, leaf: Hash) {
281 if self.leaves.is_empty() {
282 *self = Self::new(vec![leaf]);
283 return;
284 }
285 self.leaves.push(leaf);
286 self.levels[0].push(leaf);
287 let mut idx = self.levels[0].len() - 1;
288 let mut level_idx = 0;
289 loop {
290 let level = &self.levels[level_idx];
291 let pair_start = idx & !1;
292 let left = level[pair_start];
293 let right = if pair_start + 1 < level.len() {
294 level[pair_start + 1]
295 } else {
296 left
297 };
298 let parent = merge_hash_pair(left, right);
299 let parent_idx = pair_start / 2;
300 if self.levels.len() == level_idx + 1 {
301 self.levels.push(Vec::new());
302 }
303 let next = &mut self.levels[level_idx + 1];
304 if parent_idx < next.len() {
305 next[parent_idx] = parent;
306 } else {
307 next.push(parent);
308 }
309 if parent_idx == 0 && next.len() == 1 {
310 break;
311 }
312 idx = parent_idx;
313 level_idx += 1;
314 }
315 }
316
317 #[must_use]
319 pub fn root(&self) -> Hash {
320 self.levels
321 .last()
322 .and_then(|level| level.first().copied())
323 .unwrap_or_else(|| hash_bytes_with_tag(HashTag::MerkleLeaf, &[]))
324 }
325
326 #[must_use]
328 pub fn prove(&self, index: usize) -> Option<AuthProof> {
329 if index >= self.leaves.len() {
330 return None;
331 }
332 let mut idx = index;
333 let mut siblings = Vec::new();
334 let mut sibling_on_left = Vec::new();
335 for level in &self.levels {
336 if level.len() <= 1 {
337 break;
338 }
339 let pair_index = idx ^ 1;
340 let sibling = if pair_index < level.len() {
341 level[pair_index]
342 } else {
343 level[idx]
344 };
345 siblings.push(sibling);
346 sibling_on_left.push(pair_index < idx);
347 idx /= 2;
348 }
349 Some(AuthProof {
350 index,
351 siblings,
352 sibling_on_left,
353 })
354 }
355
356 #[must_use]
358 pub fn verify(root: Hash, leaf: Hash, proof: &AuthProof) -> bool {
359 if proof.siblings.len() != proof.sibling_on_left.len() {
360 return false;
361 }
362 let mut current = leaf;
363 let mut index = proof.index;
364 for (sibling, on_left) in proof.siblings.iter().zip(proof.sibling_on_left.iter()) {
365 let expected_on_left = index % 2 == 1;
366 if *on_left != expected_on_left {
367 return false;
368 }
369 current = if *on_left {
370 merge_hash_pair(*sibling, current)
371 } else {
372 merge_hash_pair(current, *sibling)
373 };
374 index /= 2;
375 }
376 current == root
377 }
378}
379
380#[cfg(test)]
381mod tests {
382 use super::*;
383
384 #[test]
385 fn signature_roundtrip() {
386 let ep = Endpoint {
387 sid: 9,
388 role: "Alice".to_string(),
389 };
390 let sk = signing_key_for_endpoint(&ep);
391 let vk = verifying_key_for_endpoint(&ep);
392 let payload = Value::Nat(42);
393 let sig = sign_value(&payload, &sk);
394 assert!(verify_signed_value(&payload, &sig, &vk));
395 assert!(!verify_signed_value(&Value::Nat(7), &sig, &vk));
396 }
397
398 #[test]
399 fn auth_tree_proof_roundtrip() {
400 let leaves = vec![
401 hash_bytes_with_tag(HashTag::MerkleLeaf, b"a"),
402 hash_bytes_with_tag(HashTag::MerkleLeaf, b"b"),
403 hash_bytes_with_tag(HashTag::MerkleLeaf, b"c"),
404 ];
405 let tree = AuthTree::new(leaves.clone());
406 let proof = tree.prove(1).expect("proof for valid index");
407 assert!(AuthTree::verify(tree.root(), leaves[1], &proof));
408 }
409
410 #[test]
411 fn auth_tree_incremental_append_matches_rebuild() {
412 let leaves = vec![
413 hash_bytes_with_tag(HashTag::MerkleLeaf, b"a"),
414 hash_bytes_with_tag(HashTag::MerkleLeaf, b"b"),
415 hash_bytes_with_tag(HashTag::MerkleLeaf, b"c"),
416 hash_bytes_with_tag(HashTag::MerkleLeaf, b"d"),
417 hash_bytes_with_tag(HashTag::MerkleLeaf, b"e"),
418 ];
419 let mut incremental = AuthTree::new(vec![leaves[0]]);
420 for leaf in leaves.iter().skip(1) {
421 incremental.append_leaf(*leaf);
422 }
423 let rebuilt = AuthTree::new(leaves);
424 assert_eq!(incremental.root(), rebuilt.root());
425 }
426}