1#![doc(
22 html_logo_url = "https://raw.githubusercontent.com/maidsafe/QA/master/Images/maidsafe_logo.png",
23 html_favicon_url = "https://maidsafe.net/img/favicon.ico",
24 test(attr(forbid(warnings)))
25)]
26#![forbid(
29 bad_style,
30 arithmetic_overflow,
31 mutable_transmutes,
32 no_mangle_const_items,
33 unknown_crate_types
34)]
35#![deny(
36 deprecated,
37 improper_ctypes,
38 missing_docs,
39 non_shorthand_field_patterns,
40 overflowing_literals,
41 stable_features,
42 unconditional_recursion,
43 unknown_lints,
44 unsafe_code,
45 unused,
46 unused_allocation,
47 unused_attributes,
48 unused_comparisons,
49 unused_features,
50 unused_parens,
51 while_true,
52 warnings
53)]
54#![warn(
55 trivial_casts,
56 trivial_numeric_casts,
57 unused_extern_crates,
58 unused_import_braces,
59 unused_qualifications,
60 unused_results
61)]
62#![allow(
63 box_pointers,
64 missing_copy_implementations,
65 missing_debug_implementations,
66 variant_size_differences
67)]
68
69use std::collections::VecDeque;
70use tiny_keccak::{Hasher, Sha3};
71
72pub struct ResourceProof {
74 min_size: usize,
75 difficulty: u8,
77}
78
79impl ResourceProof {
80 pub fn new(min_size: usize, difficulty: u8) -> ResourceProof {
88 ResourceProof {
89 min_size,
90 difficulty,
91 }
92 }
93
94 pub fn create_proof_data(&self, nonce: &[u8]) -> VecDeque<u8> {
96 nonce.iter().cloned().cycle().take(self.min_size).collect()
97 }
98
99 pub fn create_prover(&self, data: VecDeque<u8>) -> ResourceProver {
102 ResourceProver {
103 difficulty: self.difficulty,
104 count: 0,
105 data,
106 }
107 }
108
109 pub fn validate_all(&self, nonce: &[u8], received_data: &VecDeque<u8>, key: u64) -> bool {
111 let mut data = self.create_proof_data(nonce);
112 if data != *received_data {
113 return false;
114 }
115 for _ in 0..key {
116 data.push_front(0u8);
117 }
118 self.check_hash(&data) >= self.difficulty
119 }
120
121 pub fn validate_data(&self, nonce: &[u8], data: &VecDeque<u8>) -> bool {
123 self.create_proof_data(nonce) == *data
124 }
125
126 pub fn validate_proof(&self, nonce: &[u8], key: u64) -> bool {
129 let mut data = self.create_proof_data(nonce);
130 for _ in 0..key {
131 data.push_front(0u8);
132 }
133 self.check_hash(&data) >= self.difficulty
134 }
135
136 fn check_hash(&self, data: &VecDeque<u8>) -> u8 {
137 ResourceProof::leading_zeros(&hash(&data.as_slices()))
138 }
139
140 fn leading_zeros(data: &[u8]) -> u8 {
141 let mut zeros = 0u8;
142 for (count, i) in data.iter().enumerate() {
143 zeros = i.leading_zeros() as u8 + (count as u8 * 8);
144 if i.leading_zeros() < 8 {
145 break;
146 }
147 }
148 zeros
149 }
150}
151
152pub struct ResourceProver {
154 difficulty: u8,
155 count: u64,
156 data: VecDeque<u8>,
157}
158
159impl ResourceProver {
160 pub fn expected_steps(&self) -> u64 {
166 2u64.pow(u32::from(self.difficulty))
167 }
168
169 pub fn try_step(&mut self) -> Option<u64> {
173 if self.check_hash() >= self.difficulty {
174 return Some(self.count);
175 }
176
177 self.data.push_front(0u8);
178 self.count += 1;
179 None
180 }
181
182 pub fn solve(&mut self) -> u64 {
185 loop {
186 if let Some(solution) = self.try_step() {
187 return solution;
188 }
189 }
190 }
191
192 fn check_hash(&self) -> u8 {
193 ResourceProof::leading_zeros(&hash(&self.data.as_slices()))
194 }
195}
196
197pub fn nonce_from_seed(seed: &[u8]) -> [u8; 32] {
199 let mut hasher = Sha3::v256();
200 hasher.update(seed);
201
202 let mut nonce = [0u8; 32];
203 hasher.finalize(&mut nonce);
204 nonce
205}
206
207fn hash(data: &(&[u8], &[u8])) -> [u8; 32] {
209 let mut hasher = Sha3::v256();
210 let mut res = [0u8; 32];
211 hasher.update(data.0);
212 hasher.update(data.1);
213 hasher.finalize(&mut res);
214 res
215}
216
217#[cfg(test)]
218mod tests {
219 use super::*;
220
221 #[test]
222 fn valid_proof() {
223 for i in 0..20 {
224 let nonce = nonce_from_seed(&[i]);
225 let rp = ResourceProof::new(1024, 3);
226 let data = rp.create_proof_data(&nonce);
227 let proof = rp.create_prover(data.clone()).solve();
228 assert!(rp.validate_proof(&nonce, proof));
229 assert!(rp.validate_data(&nonce, &data));
230 assert!(rp.validate_all(&nonce, &data, proof));
231 }
232 }
233}