irontide_core/
hash_request.rs1use crate::Id32;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct HashRequest {
12 pub file_root: Id32,
14 pub base: u32,
16 pub index: u32,
18 pub count: u32,
20 pub proof_layers: u32,
22}
23
24#[must_use]
30pub fn validate_hash_request(
31 req: &HashRequest,
32 file_num_blocks: u32,
33 _file_num_pieces: u32,
34) -> bool {
35 if req.count == 0 || req.count > 8192 {
36 return false;
37 }
38
39 let num_leafs = file_num_blocks.next_power_of_two();
40 let num_layers = num_leafs.trailing_zeros() + 1;
41
42 if req.base >= num_layers {
43 return false;
44 }
45
46 let layer_size = num_leafs >> req.base;
48
49 if req.index >= layer_size || req.index + req.count > layer_size {
50 return false;
51 }
52
53 if req.proof_layers >= num_layers - req.base {
54 return false;
55 }
56
57 true
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63 use crate::Id32;
64
65 #[test]
66 fn valid_request_passes() {
67 let req = HashRequest {
68 file_root: Id32::ZERO,
69 base: 0,
70 index: 0,
71 count: 512,
72 proof_layers: 3,
73 };
74 assert!(validate_hash_request(&req, 8192, 512));
75 }
76
77 #[test]
78 fn reject_count_too_large() {
79 let req = HashRequest {
80 file_root: Id32::ZERO,
81 base: 0,
82 index: 0,
83 count: 8193, proof_layers: 0,
85 };
86 assert!(!validate_hash_request(&req, 16384, 8192));
87 }
88
89 #[test]
90 fn reject_index_out_of_range() {
91 let req = HashRequest {
92 file_root: Id32::ZERO,
93 base: 0,
94 index: 100,
95 count: 10,
96 proof_layers: 0,
97 };
98 assert!(!validate_hash_request(&req, 64, 4));
100 }
101
102 #[test]
103 fn reject_zero_count() {
104 let req = HashRequest {
105 file_root: Id32::ZERO,
106 base: 0,
107 index: 0,
108 count: 0,
109 proof_layers: 0,
110 };
111 assert!(!validate_hash_request(&req, 64, 4));
112 }
113
114 #[test]
115 fn piece_layer_request_valid() {
116 let req = HashRequest {
118 file_root: Id32::ZERO,
119 base: 4, index: 0,
121 count: 32,
122 proof_layers: 2,
123 };
124 assert!(validate_hash_request(&req, 512, 32));
125 }
126}