1use super::{canonical_json, BinaryWriter, EncodingError};
7use serde_json::Value;
8use sha2::{Digest, Sha256};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum HashType {
13 Sha256,
15 Sha256Json,
17 Sha256Binary,
19}
20
21#[derive(Debug, Clone, Copy)]
23pub struct AccumulateHash;
24
25impl AccumulateHash {
26 pub fn sha256_bytes(data: &[u8]) -> [u8; 32] {
29 let mut hasher = Sha256::new();
30 hasher.update(data);
31 hasher.finalize().into()
32 }
33
34 pub fn sha256_bytes_hex(data: &[u8]) -> String {
37 let hash = Self::sha256_bytes(data);
38 hex::encode(hash)
39 }
40
41 pub fn sha256_json(value: &Value) -> [u8; 32] {
44 let canonical = canonical_json(value);
45 Self::sha256_bytes(canonical.as_bytes())
46 }
47
48 pub fn sha256_json_hex(value: &Value) -> String {
51 let hash = Self::sha256_json(value);
52 hex::encode(hash)
53 }
54
55 pub fn sha256_string(text: &str) -> [u8; 32] {
58 Self::sha256_bytes(text.as_bytes())
59 }
60
61 pub fn sha256_string_hex(text: &str) -> String {
64 let hash = Self::sha256_string(text);
65 hex::encode(hash)
66 }
67
68 pub fn sha256_concat(arrays: &[&[u8]]) -> [u8; 32] {
71 let mut hasher = Sha256::new();
72 for array in arrays {
73 hasher.update(array);
74 }
75 hasher.finalize().into()
76 }
77
78 pub fn sha256_concat_hex(arrays: &[&[u8]]) -> String {
81 let hash = Self::sha256_concat(arrays);
82 hex::encode(hash)
83 }
84
85 pub fn double_sha256(data: &[u8]) -> [u8; 32] {
88 let first_hash = Self::sha256_bytes(data);
89 Self::sha256_bytes(&first_hash)
90 }
91
92 pub fn double_sha256_hex(data: &[u8]) -> String {
95 let hash = Self::double_sha256(data);
96 hex::encode(hash)
97 }
98
99 pub fn sha256_binary_encoded<T>(value: T, field: Option<u32>) -> Result<[u8; 32], EncodingError>
102 where
103 T: BinaryEncodable,
104 {
105 let binary_data = value.encode_binary()?;
106 let data = if let Some(field_num) = field {
107 BinaryWriter::with_field_number(&binary_data, Some(field_num))?
108 } else {
109 binary_data
110 };
111 Ok(Self::sha256_bytes(&data))
112 }
113
114 pub fn sha256_binary_encoded_hex<T>(
117 value: T,
118 field: Option<u32>,
119 ) -> Result<String, EncodingError>
120 where
121 T: BinaryEncodable,
122 {
123 let hash = Self::sha256_binary_encoded(value, field)?;
124 Ok(hex::encode(hash))
125 }
126
127 pub fn hash_transaction(transaction: &Value) -> [u8; 32] {
130 Self::sha256_json(transaction)
131 }
132
133 pub fn hash_transaction_hex(transaction: &Value) -> String {
135 let hash = Self::hash_transaction(transaction);
136 hex::encode(hash)
137 }
138}
139
140pub trait BinaryEncodable {
142 fn encode_binary(&self) -> Result<Vec<u8>, EncodingError>;
143}
144
145impl BinaryEncodable for u64 {
147 fn encode_binary(&self) -> Result<Vec<u8>, EncodingError> {
148 Ok(BinaryWriter::encode_uvarint(*self))
149 }
150}
151
152impl BinaryEncodable for i64 {
153 fn encode_binary(&self) -> Result<Vec<u8>, EncodingError> {
154 Ok(BinaryWriter::encode_varint(*self))
155 }
156}
157
158impl BinaryEncodable for String {
159 fn encode_binary(&self) -> Result<Vec<u8>, EncodingError> {
160 Ok(BinaryWriter::encode_string(self))
161 }
162}
163
164impl BinaryEncodable for &str {
165 fn encode_binary(&self) -> Result<Vec<u8>, EncodingError> {
166 Ok(BinaryWriter::encode_string(self))
167 }
168}
169
170impl BinaryEncodable for Vec<u8> {
171 fn encode_binary(&self) -> Result<Vec<u8>, EncodingError> {
172 Ok(BinaryWriter::encode_bytes(self))
173 }
174}
175
176impl BinaryEncodable for &[u8] {
177 fn encode_binary(&self) -> Result<Vec<u8>, EncodingError> {
178 Ok(BinaryWriter::encode_bytes(self))
179 }
180}
181
182impl BinaryEncodable for bool {
183 fn encode_binary(&self) -> Result<Vec<u8>, EncodingError> {
184 Ok(BinaryWriter::encode_bool(*self))
185 }
186}
187
188impl BinaryEncodable for [u8; 32] {
189 fn encode_binary(&self) -> Result<Vec<u8>, EncodingError> {
190 Ok(BinaryWriter::encode_hash(self))
191 }
192}
193
194#[derive(Debug, Clone, Copy)]
196pub struct UrlHash;
197
198impl UrlHash {
199 pub fn hash_url(url: &str) -> [u8; 32] {
202 let normalized = Self::normalize_url(url);
204 AccumulateHash::sha256_string(&normalized)
205 }
206
207 pub fn hash_url_hex(url: &str) -> String {
210 let hash = Self::hash_url(url);
211 hex::encode(hash)
212 }
213
214 pub fn normalize_url(url: &str) -> String {
217 let mut normalized = url.to_lowercase();
218
219 while normalized.ends_with('/') {
221 normalized.pop();
222 }
223
224 if !normalized.starts_with("acc://") {
226 if normalized.starts_with("//") {
227 normalized = format!("acc:{}", normalized);
228 } else if normalized.starts_with("/") {
229 normalized = format!("acc:/{}", normalized);
230 } else {
231 normalized = format!("acc://{}", normalized);
232 }
233 }
234
235 normalized
236 }
237
238 pub fn derive_key_book_url(identity_url: &str) -> String {
241 let normalized = Self::normalize_url(identity_url);
242 format!("{}/book", normalized)
243 }
244
245 pub fn derive_key_page_url(key_book_url: &str, page_index: u32) -> String {
248 let normalized = Self::normalize_url(key_book_url);
249 format!("{}/{}", normalized, page_index)
250 }
251
252 pub fn extract_authority(url: &str) -> Option<String> {
255 let normalized = Self::normalize_url(url);
256
257 if let Some(authority_start) = normalized.find("://") {
258 let after_protocol = &normalized[authority_start + 3..];
259 if let Some(path_start) = after_protocol.find('/') {
260 Some(after_protocol[..path_start].to_string())
261 } else {
262 Some(after_protocol.to_string())
263 }
264 } else {
265 None
266 }
267 }
268
269 pub fn extract_path(url: &str) -> String {
272 let normalized = Self::normalize_url(url);
273
274 if let Some(authority_start) = normalized.find("://") {
275 let after_protocol = &normalized[authority_start + 3..];
276 if let Some(path_start) = after_protocol.find('/') {
277 after_protocol[path_start..].to_string()
278 } else {
279 "/".to_string()
280 }
281 } else {
282 "/".to_string()
283 }
284 }
285}
286
287#[derive(Debug, Clone, Copy)]
289pub struct ChainHash;
290
291impl ChainHash {
292 pub fn hash_chain_id(url: &str) -> [u8; 32] {
295 let normalized = UrlHash::normalize_url(url);
296 AccumulateHash::sha256_string(&normalized)
297 }
298
299 pub fn hash_chain_id_hex(url: &str) -> String {
302 let hash = Self::hash_chain_id(url);
303 hex::encode(hash)
304 }
305
306 pub fn derive_main_chain_id(authority: &str) -> [u8; 32] {
309 let main_url = format!("acc://{}", authority.to_lowercase());
310 Self::hash_chain_id(&main_url)
311 }
312
313 pub fn derive_main_chain_id_hex(authority: &str) -> String {
316 let hash = Self::derive_main_chain_id(authority);
317 hex::encode(hash)
318 }
319}
320
321#[derive(Debug, Clone, Copy)]
323pub struct MerkleHash;
324
325impl MerkleHash {
326 pub fn build_merkle_root(hashes: &[[u8; 32]]) -> [u8; 32] {
329 if hashes.is_empty() {
330 return [0u8; 32];
331 }
332
333 if hashes.len() == 1 {
334 return hashes[0];
335 }
336
337 let mut current_level: Vec<[u8; 32]> = hashes.to_vec();
338
339 while current_level.len() > 1 {
340 let mut next_level = Vec::new();
341
342 for chunk in current_level.chunks(2) {
343 let combined_hash = if chunk.len() == 2 {
344 AccumulateHash::sha256_concat(&[&chunk[0], &chunk[1]])
346 } else {
347 AccumulateHash::sha256_concat(&[&chunk[0], &chunk[0]])
349 };
350 next_level.push(combined_hash);
351 }
352
353 current_level = next_level;
354 }
355
356 current_level[0]
357 }
358
359 pub fn build_merkle_root_hex(hashes: &[[u8; 32]]) -> String {
362 let root = Self::build_merkle_root(hashes);
363 hex::encode(root)
364 }
365
366 pub fn create_merkle_proof(hashes: &[[u8; 32]], index: usize) -> Vec<[u8; 32]> {
369 if hashes.is_empty() || index >= hashes.len() {
370 return Vec::new();
371 }
372
373 if hashes.len() == 1 {
374 return Vec::new();
375 }
376
377 let mut proof = Vec::new();
378 let mut current_level: Vec<[u8; 32]> = hashes.to_vec();
379 let mut current_index = index;
380
381 while current_level.len() > 1 {
382 let sibling_index = if current_index % 2 == 0 {
384 current_index + 1
385 } else {
386 current_index - 1
387 };
388
389 if sibling_index < current_level.len() {
390 proof.push(current_level[sibling_index]);
391 } else {
392 proof.push(current_level[current_index]);
394 }
395
396 let mut next_level = Vec::new();
398 for chunk in current_level.chunks(2) {
399 let combined_hash = if chunk.len() == 2 {
400 AccumulateHash::sha256_concat(&[&chunk[0], &chunk[1]])
401 } else {
402 AccumulateHash::sha256_concat(&[&chunk[0], &chunk[0]])
403 };
404 next_level.push(combined_hash);
405 }
406
407 current_level = next_level;
408 current_index /= 2;
409 }
410
411 proof
412 }
413
414 pub fn verify_merkle_proof(
417 root: &[u8; 32],
418 leaf: &[u8; 32],
419 proof: &[[u8; 32]],
420 index: usize,
421 ) -> bool {
422 let mut computed_hash = *leaf;
423 let mut current_index = index;
424
425 for sibling in proof {
426 computed_hash = if current_index % 2 == 0 {
427 AccumulateHash::sha256_concat(&[&computed_hash, sibling])
428 } else {
429 AccumulateHash::sha256_concat(&[sibling, &computed_hash])
430 };
431 current_index /= 2;
432 }
433
434 &computed_hash == root
435 }
436}
437
438#[cfg(test)]
439mod tests {
440 use super::*;
441 use serde_json::json;
442
443 #[test]
444 fn test_sha256_consistency() {
445 let data = b"hello world";
446 let hash1 = AccumulateHash::sha256_bytes(data);
447 let hash2 = AccumulateHash::sha256_bytes(data);
448 assert_eq!(hash1, hash2);
449
450 let hex1 = AccumulateHash::sha256_bytes_hex(data);
451 let hex2 = AccumulateHash::sha256_bytes_hex(data);
452 assert_eq!(hex1, hex2);
453 assert_eq!(hex1, hex::encode(hash1));
454 }
455
456 #[test]
457 fn test_json_hashing() {
458 let value = json!({
459 "name": "test",
460 "value": 42,
461 "array": [1, 2, 3]
462 });
463
464 let hash1 = AccumulateHash::sha256_json(&value);
465 let hash2 = AccumulateHash::sha256_json(&value);
466 assert_eq!(hash1, hash2);
467
468 let value2 = json!({
470 "value": 42,
471 "array": [1, 2, 3],
472 "name": "test"
473 });
474
475 let hash3 = AccumulateHash::sha256_json(&value2);
476 assert_eq!(hash1, hash3);
477 }
478
479 #[test]
480 fn test_url_normalization() {
481 let test_cases = vec![
482 ("acc://alice.acme", "acc://alice.acme"),
483 ("ACC://ALICE.ACME", "acc://alice.acme"),
484 ("acc://alice.acme/", "acc://alice.acme"),
485 ("acc://alice.acme///", "acc://alice.acme"),
486 ("//alice.acme", "acc://alice.acme"),
487 ("alice.acme", "acc://alice.acme"),
488 ("/alice.acme", "acc://alice.acme"),
489 ];
490
491 for (input, expected) in test_cases {
492 let normalized = UrlHash::normalize_url(input);
493 assert_eq!(normalized, expected, "Failed for input: {}", input);
494 }
495 }
496
497 #[test]
498 fn test_url_hashing() {
499 let url = "acc://alice.acme";
500 let hash1 = UrlHash::hash_url(url);
501 let hash2 = UrlHash::hash_url("ACC://ALICE.ACME/");
502 assert_eq!(
503 hash1, hash2,
504 "URL hashing should be case and trailing slash insensitive"
505 );
506
507 let hex = UrlHash::hash_url_hex(url);
508 assert_eq!(hex, hex::encode(hash1));
509 }
510
511 #[test]
512 fn test_url_derivation() {
513 let identity_url = "acc://alice.acme";
514 let key_book_url = UrlHash::derive_key_book_url(identity_url);
515 assert_eq!(key_book_url, "acc://alice.acme/book");
516
517 let key_page_url = UrlHash::derive_key_page_url(&key_book_url, 0);
518 assert_eq!(key_page_url, "acc://alice.acme/book/0");
519 }
520
521 #[test]
522 fn test_url_parsing() {
523 let url = "acc://alice.acme/tokens";
524 let authority = UrlHash::extract_authority(url).unwrap();
525 assert_eq!(authority, "alice.acme");
526
527 let path = UrlHash::extract_path(url);
528 assert_eq!(path, "/tokens");
529
530 let root_url = "acc://alice.acme";
531 let root_path = UrlHash::extract_path(root_url);
532 assert_eq!(root_path, "/");
533 }
534
535 #[test]
536 fn test_chain_id_hashing() {
537 let url = "acc://alice.acme";
538 let chain_id1 = ChainHash::hash_chain_id(url);
539 let chain_id2 = ChainHash::hash_chain_id("ACC://ALICE.ACME/");
540 assert_eq!(chain_id1, chain_id2);
541
542 let main_chain_id = ChainHash::derive_main_chain_id("alice.acme");
543 assert_eq!(chain_id1, main_chain_id);
544 }
545
546 #[test]
547 fn test_merkle_tree() {
548 let hashes = vec![[1u8; 32], [2u8; 32], [3u8; 32], [4u8; 32]];
549
550 let root = MerkleHash::build_merkle_root(&hashes);
551 assert_ne!(root, [0u8; 32]);
552
553 let single_root = MerkleHash::build_merkle_root(&hashes[0..1]);
555 assert_eq!(single_root, hashes[0]);
556
557 let empty_root = MerkleHash::build_merkle_root(&[]);
559 assert_eq!(empty_root, [0u8; 32]);
560 }
561
562 #[test]
563 fn test_merkle_proof() {
564 let hashes = vec![[1u8; 32], [2u8; 32], [3u8; 32], [4u8; 32]];
565
566 let root = MerkleHash::build_merkle_root(&hashes);
567 let proof = MerkleHash::create_merkle_proof(&hashes, 0);
568
569 let is_valid = MerkleHash::verify_merkle_proof(&root, &hashes[0], &proof, 0);
570 assert!(is_valid);
571
572 let invalid_proof = MerkleHash::create_merkle_proof(&hashes, 1);
574 let is_invalid = MerkleHash::verify_merkle_proof(&root, &hashes[0], &invalid_proof, 0);
575 assert!(!is_invalid);
576 }
577
578 #[test]
579 fn test_double_hash() {
580 let data = b"test data";
581 let single_hash = AccumulateHash::sha256_bytes(data);
582 let double_hash = AccumulateHash::double_sha256(data);
583
584 assert_ne!(single_hash, double_hash);
585 assert_eq!(double_hash, AccumulateHash::sha256_bytes(&single_hash));
586 }
587
588 #[test]
589 fn test_concat_hash() {
590 let arrays = [b"hello".as_slice(), b" ".as_slice(), b"world".as_slice()];
591 let concat_hash = AccumulateHash::sha256_concat(&arrays);
592 let direct_hash = AccumulateHash::sha256_bytes(b"hello world");
593 assert_eq!(concat_hash, direct_hash);
594 }
595
596 #[test]
597 fn test_binary_encodable() {
598 let test_u64 = 12345u64;
599 let encoded = test_u64.encode_binary().unwrap();
600 assert_eq!(encoded, BinaryWriter::encode_uvarint(test_u64));
601
602 let test_string = "hello";
603 let encoded = test_string.encode_binary().unwrap();
604 assert_eq!(encoded, BinaryWriter::encode_string(test_string));
605
606 let test_bytes = vec![1, 2, 3, 4];
607 let encoded = test_bytes.encode_binary().unwrap();
608 assert_eq!(encoded, BinaryWriter::encode_bytes(&test_bytes));
609 }
610}