ab_farmer_components/
shard_commitment.rs1use ab_core_primitives::hashes::Blake3Hash;
4use ab_core_primitives::segments::{HistorySize, SegmentIndex};
5use ab_core_primitives::shard::NumShards;
6use ab_core_primitives::solutions::{
7 ShardCommitmentHash, ShardMembershipEntropy, SolutionShardCommitment,
8};
9use ab_io_type::trivial_type::TrivialType;
10use ab_merkle_tree::unbalanced::UnbalancedMerkleTree;
11use blake3::Hasher;
12use parking_lot::RwLock;
13use schnellru::{ByLength, LruMap};
14use std::iter;
15use std::mem::MaybeUninit;
16use std::sync::Arc;
17
18const SHARD_COMMITMENTS_ROOT_CACHE_SIZE: ByLength = ByLength::new(32);
19
20#[derive(Debug)]
21struct Inner {
22 shard_commitments_seed: Blake3Hash,
23 lru: LruMap<HistorySize, ShardCommitmentHash, ByLength>,
24}
25
26#[derive(Debug, Clone)]
28pub struct ShardCommitmentsRootsCache {
29 inner: Arc<RwLock<Inner>>,
30}
31
32impl ShardCommitmentsRootsCache {
33 pub fn new(shard_commitments_seed: Blake3Hash) -> Self {
35 Self {
36 inner: Arc::new(RwLock::new(Inner {
37 shard_commitments_seed,
38 lru: LruMap::new(SHARD_COMMITMENTS_ROOT_CACHE_SIZE),
39 })),
40 }
41 }
42
43 pub fn shard_commitments_seed(&self) -> Blake3Hash {
45 self.inner.read().shard_commitments_seed
46 }
47
48 pub fn get(&self, history_size: HistorySize) -> ShardCommitmentHash {
52 if let Some(root) = self.inner.read().lru.peek(&history_size).copied() {
53 return root;
54 }
55
56 let inner = &mut *self.inner.write();
57 *inner
60 .lru
61 .get_or_insert(history_size, || {
62 derive_shard_commitments_root(&inner.shard_commitments_seed, history_size)
63 })
64 .expect("Not limited by memory; qed")
65 }
66}
67
68pub fn derive_shard_commitments_root(
70 shard_commitments_seed: &Blake3Hash,
71 history_size: HistorySize,
72) -> ShardCommitmentHash {
73 let mut stream = {
74 let mut hasher = Hasher::new_keyed(shard_commitments_seed);
75 hasher.update(SegmentIndex::from(history_size).as_bytes());
76 hasher.finalize_xof()
77 };
78
79 let mut index = 0;
80 let leaves = iter::from_fn(|| {
81 if index < SolutionShardCommitment::NUM_LEAVES {
82 let mut bytes = [0; ShardCommitmentHash::SIZE];
83 stream.fill(&mut bytes);
84
85 index += 1;
86
87 Some(bytes)
88 } else {
89 None
90 }
91 });
92
93 let root = UnbalancedMerkleTree::compute_root_only::<
96 { SolutionShardCommitment::NUM_LEAVES as u64 },
97 _,
98 _,
99 >(leaves)
100 .expect("List of leaves is not empty; qed");
101
102 ShardCommitmentHash::new(root)
103}
104
105pub fn derive_solution_shard_commitment(
107 public_key_hash: &Blake3Hash,
108 shard_commitments_seed: &Blake3Hash,
109 shard_commitments_root: &ShardCommitmentHash,
110 history_size: HistorySize,
111 shard_membership_entropy: &ShardMembershipEntropy,
112 num_shards: NumShards,
113) -> SolutionShardCommitment {
114 let mut stream = {
115 let mut hasher = Hasher::new_keyed(shard_commitments_seed);
116 hasher.update(SegmentIndex::from(history_size).as_bytes());
117 hasher.finalize_xof()
118 };
119
120 let leaf_index = num_shards.derive_shard_commitment_index(
121 public_key_hash,
122 shard_commitments_root,
123 shard_membership_entropy,
124 history_size,
125 ) as usize;
126
127 let mut leaf = [0; _];
128 let mut index = 0;
129 let leaves = iter::from_fn(|| {
130 if index < SolutionShardCommitment::NUM_LEAVES {
131 let mut bytes = [0; ShardCommitmentHash::SIZE];
132 stream.fill(&mut bytes);
133
134 if index == leaf_index {
135 leaf = bytes;
136 }
137
138 index += 1;
139
140 Some(bytes)
141 } else {
142 None
143 }
144 });
145
146 let mut proof = [MaybeUninit::uninit(); _];
147 let (_root, computed_proof) = UnbalancedMerkleTree::compute_root_and_proof_in::<
150 { SolutionShardCommitment::NUM_LEAVES as u64 },
151 _,
152 _,
153 >(leaves, leaf_index, &mut proof)
154 .expect("Index is always within the list of leaves; qed");
155 debug_assert_eq!(computed_proof.len(), proof.len());
156
157 let proof = unsafe { MaybeUninit::array_assume_init(proof) };
159
160 SolutionShardCommitment {
161 root: *shard_commitments_root,
162 proof: ShardCommitmentHash::array_from_repr(proof),
163 leaf: ShardCommitmentHash::new(leaf),
164 }
165}