ab_proof_of_space/
shim.rs1#[cfg(feature = "alloc")]
5use crate::PosProofs;
6#[cfg(feature = "alloc")]
7use crate::TableGenerator;
8use crate::{PosTableType, Table};
9#[cfg(feature = "alloc")]
10use ab_core_primitives::pieces::Record;
11use ab_core_primitives::pos::{PosProof, PosSeed};
12use ab_core_primitives::sectors::SBucket;
13#[cfg(feature = "alloc")]
14use alloc::boxed::Box;
15use core::iter;
16
17#[derive(Debug, Default, Clone)]
21#[cfg(feature = "alloc")]
22pub struct ShimTableGenerator;
23
24#[cfg(feature = "alloc")]
25impl TableGenerator<ShimTable> for ShimTableGenerator {
26 fn create_proofs(&self, seed: &PosSeed) -> Box<PosProofs> {
27 let mut proofs = unsafe { Box::<PosProofs>::new_zeroed().assume_init() };
29
30 let mut num_found_proofs = 0_usize;
31 'outer: for (s_buckets, found_proofs) in (0..Record::NUM_S_BUCKETS as u32)
32 .array_chunks::<{ u8::BITS as usize }>()
33 .zip(&mut proofs.found_proofs)
34 {
35 for (proof_offset, s_bucket) in s_buckets.into_iter().enumerate() {
36 if let Some(proof) = find_proof(seed, s_bucket) {
37 *found_proofs |= 1 << proof_offset;
38
39 proofs.proofs[num_found_proofs] = proof;
40 num_found_proofs += 1;
41
42 if num_found_proofs == Record::NUM_CHUNKS {
43 break 'outer;
44 }
45 }
46 }
47 }
48
49 proofs
50 }
51}
52
53#[derive(Debug)]
57pub struct ShimTable;
58
59impl ab_core_primitives::solutions::SolutionPotVerifier for ShimTable {
60 fn is_proof_valid(seed: &PosSeed, s_bucket: SBucket, proof: &PosProof) -> bool {
61 let Some(correct_proof) = find_proof(seed, u32::from(s_bucket)) else {
62 return false;
63 };
64
65 &correct_proof == proof
66 }
67}
68
69impl Table for ShimTable {
70 const TABLE_TYPE: PosTableType = PosTableType::Shim;
71 #[cfg(feature = "alloc")]
72 type Generator = ShimTableGenerator;
73
74 fn is_proof_valid(seed: &PosSeed, s_bucket: SBucket, proof: &PosProof) -> bool {
75 <Self as ab_core_primitives::solutions::SolutionPotVerifier>::is_proof_valid(
76 seed, s_bucket, proof,
77 )
78 }
79}
80
81fn find_proof(seed: &PosSeed, challenge_index: u32) -> Option<PosProof> {
82 let quality = ab_blake3::single_block_hash(&challenge_index.to_le_bytes())
83 .expect("Less than a single block worth of bytes; qed");
84 if !quality[0].is_multiple_of(3) {
85 let mut proof = PosProof::default();
86 proof
87 .iter_mut()
88 .zip(seed.iter().chain(iter::repeat(quality.iter()).flatten()))
89 .for_each(|(output, input)| {
90 *output = *input;
91 });
92
93 Some(proof)
94 } else {
95 None
96 }
97}
98
99#[cfg(all(feature = "alloc", test, not(miri)))]
100mod tests {
101 use super::*;
102
103 #[test]
104 fn basic() {
105 let seed = PosSeed::from([
106 35, 2, 52, 4, 51, 55, 23, 84, 91, 10, 111, 12, 13, 222, 151, 16, 228, 211, 254, 45, 92,
107 198, 204, 10, 9, 10, 11, 129, 139, 171, 15, 23,
108 ]);
109
110 let proofs = ShimTable::generator().create_proofs(&seed);
111
112 let s_bucket_without_proof = SBucket::from(1);
113 assert!(proofs.for_s_bucket(s_bucket_without_proof).is_none());
114
115 {
116 let s_bucket_with_proof = SBucket::from(0);
117 let proof = proofs.for_s_bucket(s_bucket_with_proof).unwrap();
118 assert!(ShimTable::is_proof_valid(
119 &seed,
120 s_bucket_with_proof,
121 &proof
122 ));
123 }
124 }
125}