stable_hash/crypto/
hasher.rs1use super::address::CryptoAddress;
2use crate::prelude::*;
3use blake3::Hasher;
4use ibig::UBig;
5use lazy_static::lazy_static;
6use num_traits::{identities::One, Zero};
7use std::default::Default;
8
9lazy_static! {
18 static ref P: UBig = "50763434429823703141085322590076158163032399096130816327134180611270739679038131809123861970975131471260684737408234060876742190838745219274061025048845231234136148410311444604554192918702297959809128216170781389312847013812749872750274650041183009144583521632294518996531883338553737214586176414455965584933129379474747808392433032576309945590584603359054260866543918929486383805924215982747035136255123252119828736134723149397165643360162699752374292974151421555939481822911026769138419707577501643119472226283015793622652706604535623136902831581637275314074553942039263472515423713366344495524733341031029964603383".parse().unwrap();
19}
20
21#[derive(Clone, Eq, PartialEq, Debug)]
32pub struct CryptoStableHasher {
33 value: UBig,
38}
39
40impl Default for CryptoStableHasher {
41 fn default() -> Self {
42 Self { value: UBig::one() }
43 }
44}
45
46#[inline]
47fn mul_mod_p(into: &mut UBig, value: &UBig) {
48 profile_method!(mul_mod_p);
49 *into *= value;
50 *into %= &*P;
51}
52
53impl StableHasher for CryptoStableHasher {
54 type Out = [u8; 32];
55 type Addr = CryptoAddress;
56 type Bytes = Vec<u8>;
57
58 #[inline]
59 fn new() -> Self {
60 profile_method!(new);
61
62 Default::default()
63 }
64
65 fn write(&mut self, field_address: Self::Addr, bytes: &[u8]) {
66 profile_method!(write);
67
68 let mut output = field_address.finish(bytes);
70 let mut digits = [0u8; 256];
73 output.fill(&mut digits);
74 let digits = UBig::from_le_bytes(&digits);
75 mul_mod_p(&mut self.value, &digits);
76 }
77
78 #[inline]
79 fn mixin(&mut self, other: &Self) {
80 mul_mod_p(&mut self.value, &other.value);
81 }
82
83 fn unmix(&mut self, other: &Self) {
84 let mut todo = Vec::with_capacity(2049);
87
88 let mut y = &*P - UBig::from(2u32);
90 while !y.is_zero() {
91 todo.push(y.clone());
92 y = y / 2;
93 }
94 let mut p = UBig::one();
95 while let Some(next) = todo.pop() {
96 let clone = p.clone();
97 mul_mod_p(&mut p, &clone);
98 if next % 2 != 0 {
99 mul_mod_p(&mut p, &other.value);
100 }
101 }
102
103 mul_mod_p(&mut self.value, &p);
105 }
106
107 fn finish(&self) -> Self::Out {
108 profile_method!(finish);
109
110 let mut hasher = Hasher::new();
112 let le = self.value.to_le_bytes();
113 hasher.update(&le);
114 hasher.finalize().into()
115 }
116
117 fn to_bytes(&self) -> Self::Bytes {
118 profile_method!(to_bytes);
119 self.value.to_le_bytes()
120 }
121 fn from_bytes(bytes: Vec<u8>) -> Self {
124 profile_method!(from_bytes);
125
126 let value = UBig::from_le_bytes(&bytes);
127 assert!(&value <= &*P);
128 Self { value }
129 }
130}
131
132#[cfg(test)]
133impl CryptoStableHasher {
134 pub(crate) fn rand() -> Self {
135 use rand::Rng;
136 loop {
137 let mut bytes = Vec::new();
138 for _ in 0..257 {
139 let rand_byte: u8 = rand::thread_rng().gen();
140 if bytes.len() == 0 && rand_byte == 0 {
141 continue;
142 }
143 bytes.push(rand_byte);
144 }
145 let big = UBig::from_be_bytes(&bytes);
146 if &big >= &*P {
147 continue;
148 }
149 return CryptoStableHasher { value: big };
150 }
151 }
152}