-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Implemented namespace hash digest (#101)
* feat : Implementing helper fns * feat : Draft PR (namespace hash digest and namespace merkle tree) * feat : Implemented namespace message digest and added tests --------- Co-authored-by: Brandon Roberts <[email protected]>
- Loading branch information
1 parent
d5fcd3d
commit 01c1ad6
Showing
5 changed files
with
180 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
use alexandria_bytes::Bytes; | ||
use alexandria_bytes::BytesTrait; | ||
use alexandria_math::U256BitShift; | ||
use blobstream_sn::tree::consts::{LEAF_PREFIX, NODE_PREFIX, parity_share_namespace}; | ||
use blobstream_sn::tree::namespace::merkle_tree::{ | ||
Namespace, NamespaceNode, NamespaceMerkleMultiproof, NamespaceMerkleProof | ||
}; | ||
|
||
fn leaf_digest(namespace: Namespace, data: @Bytes) -> NamespaceNode { | ||
let mut bytes = BytesTrait::new_empty(); | ||
bytes.append_u8(LEAF_PREFIX); | ||
bytes.append_u8(namespace.version); | ||
append_bytes28(ref bytes, namespace.id); | ||
bytes.concat(data); | ||
return NamespaceNode { min: namespace, max: namespace, digest: bytes.sha256() }; | ||
} | ||
|
||
fn namespace_min(l: Namespace, r: Namespace) -> Namespace { | ||
if l < r { | ||
return l; | ||
} | ||
return r; | ||
} | ||
|
||
fn namespace_max(l: Namespace, r: Namespace) -> Namespace { | ||
if l > r { | ||
return l; | ||
} | ||
return r; | ||
} | ||
|
||
fn node_digest(left: NamespaceNode, right: NamespaceNode) -> NamespaceNode { | ||
let mut min: Namespace = namespace_min(left.min, right.min); | ||
let mut max: Namespace = namespace_max(left.max, right.max); | ||
if (left.min == parity_share_namespace()) { | ||
max = parity_share_namespace(); | ||
} else if (right.min == parity_share_namespace()) { | ||
max = left.max; | ||
} | ||
|
||
let mut bytes = BytesTrait::new_empty(); | ||
bytes.append_u8(NODE_PREFIX); | ||
bytes.append_u8(left.min.version); | ||
append_bytes28(ref bytes, left.min.id); | ||
bytes.append_u8(left.max.version); | ||
append_bytes28(ref bytes, left.max.id); | ||
bytes.append_u256(left.digest); | ||
bytes.append_u8(right.min.version); | ||
append_bytes28(ref bytes, right.min.id); | ||
bytes.append_u8(right.max.version); | ||
append_bytes28(ref bytes, right.max.id); | ||
bytes.append_u256(right.digest); | ||
|
||
return NamespaceNode { min: min, max: max, digest: bytes.sha256() }; | ||
} | ||
|
||
fn append_bytes28(ref self: Bytes, value: bytes31) { | ||
let mut value_u256: u256 = value.into(); | ||
value_u256 = U256BitShift::shl(value_u256, 32); | ||
let mut bytes28Bytes: Bytes = BytesTrait::new(28, array![value_u256.high, value_u256.low]); | ||
self.concat(@bytes28Bytes); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
use alexandria_bytes::BytesTrait; | ||
use blobstream_sn::tree::consts::{parity_share_namespace}; | ||
use blobstream_sn::tree::namespace::hasher::{leaf_digest, node_digest}; | ||
use blobstream_sn::tree::namespace::merkle_tree::{Namespace, NamespaceNode, namespace_node_eq}; | ||
use core::option::OptionTrait; | ||
use core::traits::Into; | ||
|
||
#[test] | ||
fn leaf_digest_empty_test() { | ||
let bytesval: bytes31 = bytes31_const::< | ||
0x00000000000000000000000000000000000000000000000000000000 | ||
>(); | ||
|
||
let nid: Namespace = Namespace { version: 0x00, id: bytesval }; | ||
|
||
let expected: NamespaceNode = NamespaceNode { | ||
min: nid, | ||
max: nid, | ||
digest: 0x0679246d6c4216de0daa08e5523fb2674db2b6599c3b72ff946b488a15290b62 | ||
}; | ||
|
||
let data = BytesTrait::new_empty(); | ||
|
||
let node: NamespaceNode = leaf_digest(nid, @data); | ||
|
||
let res = namespace_node_eq(node, expected); | ||
assert!(res, "Not equal to expected digest"); | ||
} | ||
|
||
#[test] | ||
fn test_leaf_digest_some() { | ||
let bytesval: bytes31 = bytes31_const::< | ||
0xadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefde | ||
>(); | ||
let nid = Namespace { version: 0xde, id: bytesval, }; | ||
|
||
let expected = NamespaceNode { | ||
min: nid, | ||
max: nid, | ||
digest: 0x3624c7f7169cb5bbd0d010b851ebd0edca10b2a1b126f5fb1a6d5e0d98356e63 | ||
}; | ||
|
||
let mut data = BytesTrait::new_empty(); | ||
data.append_u8(0x69); | ||
|
||
let node = leaf_digest(nid, @data); | ||
assert!(node.digest == expected.digest, "Not equal to expected digest"); | ||
} | ||
|
||
#[test] | ||
fn test_node_digest() { | ||
let nid_left = Namespace { | ||
version: 0x00, | ||
id: bytes31_const::<0x00000000000000000000000000000000000000000000000000000000>() | ||
}; | ||
let nid_right = Namespace { | ||
version: 0xde, | ||
id: bytes31_const::<0xadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefde>() | ||
}; | ||
let expected = NamespaceNode { | ||
min: nid_left, | ||
max: nid_right, | ||
digest: 0x95cad48bc181484c851004cf772abe767391e19549d3b8192b55b1d654a71bcd | ||
}; | ||
let left = NamespaceNode { | ||
min: nid_left, | ||
max: nid_left, | ||
digest: 0xdb55da3fc3098e9c42311c6013304ff36b19ef73d12ea932054b5ad51df4f49d | ||
}; | ||
|
||
let right = NamespaceNode { | ||
min: nid_right, | ||
max: nid_right, | ||
digest: 0xc75cb66ae28d8ebc6eded002c28a8ba0d06d3a78c6b5cbf9b2ade051f0775ac4 | ||
}; | ||
let node = node_digest(left, right); | ||
let res = namespace_node_eq(node, expected); | ||
assert!(res, "Not equal to expected digest"); | ||
} | ||
|
||
#[test] | ||
fn test_node_parity() { | ||
let nid_min = Namespace { | ||
version: 0x00, | ||
id: bytes31_const::<0x00000000000000000000000000000000000000000000000000000000>() | ||
}; | ||
let nid_max = Namespace { | ||
version: 0xde, | ||
id: bytes31_const::<0xadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefde>() | ||
}; | ||
let expected = NamespaceNode { | ||
min: nid_min, | ||
max: nid_max, | ||
digest: 0xc6960f535d4ab0aed075aed34a116725e8035012ceffe5405ae72abe3bcaa28f | ||
}; | ||
|
||
let left = NamespaceNode { | ||
min: nid_min, | ||
max: nid_max, | ||
digest: 0xdb55da3fc3098e9c42311c6013304ff36b19ef73d12ea932054b5ad51df4f49d | ||
}; | ||
|
||
let right = NamespaceNode { | ||
min: parity_share_namespace(), | ||
max: parity_share_namespace(), | ||
digest: 0xc75cb66ae28d8ebc6eded002c28a8ba0d06d3a78c6b5cbf9b2ade051f0775ac4 | ||
}; | ||
|
||
let node = node_digest(left, right); | ||
let res = namespace_node_eq(node, expected); | ||
assert!(res, "Not equal to expected digest"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters