blake3_proof_of_work/
lib.rs1pub const NONCE_SIZE: usize = 10usize;
12
13#[derive(Debug)]
15pub enum Error {
16 Rand(rand::Error),
17 MeterOverdrawn,
18}
19
20impl From<rand::Error> for Error {
21 fn from(error: rand::Error) -> Error {
22 Error::Rand(error)
23 }
24}
25
26pub fn search(bytes: &[u8], cost: u32, meter: u32) -> Result<[u8; NONCE_SIZE], Error> {
37 use rand::Fill;
38 let mut rng = rand::thread_rng();
39 let mut nonce = [0u8; NONCE_SIZE];
40 let mut counter = 0;
41 loop {
42 nonce.try_fill(&mut rng)?;
43 let mut hasher = blake3::Hasher::new();
44 hasher.update(&nonce);
45 hasher.update(bytes);
46 let hash = hasher.finalize();
47 if leading_zeros(hash.as_bytes()) >= cost {
48 break;
49 }
50 counter += 1;
51 if counter > meter {
52 return Err(Error::MeterOverdrawn);
53 }
54 }
55 Ok(nonce)
56}
57
58pub fn verify(bytes: &[u8], nonce: [u8; NONCE_SIZE], cost: u32) -> bool {
65 let mut hasher = blake3::Hasher::new();
66 hasher.update(&nonce);
67 hasher.update(bytes);
68 let hash = hasher.finalize();
69 leading_zeros(hash.as_bytes()) >= cost
70}
71
72pub fn leading_zeros(bytes: &[u8]) -> u32 {
74 let mut count = 0;
75 let mut ptr = bytes;
76 loop {
77 if ptr.len() == 0 {
78 break;
79 } else {
80 let lz = ptr[0].leading_zeros();
81 ptr = &ptr[1..];
82 count += lz;
83 if lz < 8 {
84 break;
85 }
86 }
87 }
88 count
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94 #[test]
95 fn leading_zeros_works() {
96 assert_eq!(leading_zeros(b"\x4f"), 1);
97 assert_eq!(leading_zeros(b"\x2f"), 2);
98 assert_eq!(leading_zeros(b"\x1f"), 3);
99 assert_eq!(leading_zeros(b"\x0f"), 4);
100 assert_eq!(leading_zeros(b"\x06"), 5);
101 assert_eq!(leading_zeros(b"\x02"), 6);
102 assert_eq!(leading_zeros(b"\x01"), 7);
103 assert_eq!(leading_zeros(b"\x00"), 8);
104 assert_eq!(leading_zeros(b"\x00\x4f"), 9);
105 assert_eq!(leading_zeros(b"\x00\x01"), 15);
106 assert_eq!(leading_zeros(b"\x00\x00"), 16);
107 assert_eq!(leading_zeros(&[0; 10000]), 10000 * 8);
108 assert_eq!(leading_zeros(&[255; 10000]), 0);
109 }
110
111 #[test]
112 fn search_works() -> Result<(), Error> {
113 let cost = 20;
114 let meter = 100000000;
115 let bytes = b"124124125124214121";
116 let nonce = search(bytes, cost, meter)?;
117 assert!(verify(bytes, nonce, cost));
118 for _i in 1..5 {
119 let nonce = search(bytes, cost, meter)?;
120 assert!(verify(bytes, nonce, cost));
121 }
122 Ok(())
123 }
124}