risc0_zkp/core/hash/
blake2b.rs1use alloc::{boxed::Box, rc::Rc, vec::Vec};
17use core::marker::PhantomData;
18
19use blake2::{
20 digest::{Update, VariableOutput},
21 Blake2bVar,
22};
23use rand_core::{impls, RngCore};
24use risc0_core::field::{
25 baby_bear::{BabyBear, BabyBearElem, BabyBearExtElem},
26 Elem, ExtElem,
27};
28
29use super::{HashFn, HashSuite, Rng, RngFactory};
30use crate::core::digest::Digest;
31
32pub trait Blake2b: Send + Sync {
34 fn blake2b<T: AsRef<[u8]>>(data: T) -> [u8; 32];
36}
37
38pub struct Blake2bCpuImpl;
40
41pub type Blake2bCpuHashSuite = Blake2bHashSuite<Blake2bCpuImpl>;
43
44impl Blake2b for Blake2bCpuImpl {
45 fn blake2b<T: AsRef<[u8]>>(data: T) -> [u8; 32] {
46 let mut result = [0; 32];
47 let mut hasher = Blake2bVar::new(32).expect("Initializing Blake2bVar failed");
48
49 hasher.update(data.as_ref());
50 hasher
51 .finalize_variable(&mut result)
52 .expect("Finalizing Blake2bVar failed");
53 result
54 }
55}
56
57struct Blake2bRngFactory<T: Blake2b> {
58 phantom: PhantomData<T>,
59}
60
61impl<T: Blake2b> Blake2bRngFactory<T> {
62 fn new() -> Self {
63 Self {
64 phantom: PhantomData,
65 }
66 }
67}
68
69impl<T: Blake2b + 'static> RngFactory<BabyBear> for Blake2bRngFactory<T> {
70 fn new_rng(&self) -> Box<dyn Rng<BabyBear>> {
71 let rng: Blake2bRng<T> = Blake2bRng::new();
72 Box::new(rng)
73 }
74}
75
76pub struct Blake2bHashSuite<T: Blake2b> {
79 phantom: PhantomData<T>,
80}
81
82impl<T: Blake2b + 'static> Blake2bHashSuite<T> {
83 pub fn new_suite() -> HashSuite<BabyBear> {
85 HashSuite {
86 name: "blake2b".into(),
87 hashfn: Rc::new(Blake2bHashFn::<T>::new()),
88 rng: Rc::new(Blake2bRngFactory::<T>::new()),
89 }
90 }
91}
92
93struct Blake2bHashFn<T: Blake2b> {
95 phantom: PhantomData<T>,
96}
97
98impl<T: Blake2b> Blake2bHashFn<T> {
99 fn new() -> Self {
100 Self {
101 phantom: PhantomData,
102 }
103 }
104}
105
106impl<T: Blake2b> HashFn<BabyBear> for Blake2bHashFn<T> {
107 fn hash_pair(&self, a: &Digest, b: &Digest) -> Box<Digest> {
108 let concat = [a.as_bytes(), b.as_bytes()].concat();
109 Box::new(Digest::from(T::blake2b(concat)))
110 }
111
112 fn hash_elem_slice(&self, slice: &[BabyBearElem]) -> Box<Digest> {
113 let mut data = Vec::<u8>::new();
114 for el in slice {
115 data.extend_from_slice(el.as_u32_montgomery().to_be_bytes().as_slice());
116 }
117 Box::new(Digest::from(T::blake2b(data)))
118 }
119
120 fn hash_ext_elem_slice(&self, slice: &[BabyBearExtElem]) -> Box<Digest> {
121 let mut data = Vec::<u8>::new();
122 for ext_el in slice {
123 for el in ext_el.subelems() {
124 data.extend_from_slice(el.as_u32_montgomery().to_be_bytes().as_slice());
125 }
126 }
127 Box::new(Digest::from(T::blake2b(data)))
128 }
129}
130
131pub struct Blake2bRng<T: Blake2b> {
133 current: [u8; 32],
134 hasher: PhantomData<T>,
135}
136
137impl<T: Blake2b> Blake2bRng<T> {
138 fn new() -> Self {
139 Self {
140 current: [0; 32],
141 hasher: Default::default(),
142 }
143 }
144}
145
146impl<T: Blake2b> Rng<BabyBear> for Blake2bRng<T> {
147 fn mix(&mut self, val: &Digest) {
148 let concat = [self.current.as_ref(), val.as_bytes()].concat();
149 self.current = T::blake2b(concat);
150 }
151
152 fn random_bits(&mut self, bits: usize) -> u32 {
153 ((1 << bits) - 1) & self.next_u32()
154 }
155
156 fn random_elem(&mut self) -> BabyBearElem {
157 BabyBearElem::random(self)
158 }
159
160 fn random_ext_elem(&mut self) -> BabyBearExtElem {
161 BabyBearExtElem::random(self)
162 }
163}
164
165impl<T: Blake2b> RngCore for Blake2bRng<T> {
166 fn next_u32(&mut self) -> u32 {
167 let next = T::blake2b(self.current);
168 self.current = next;
169 ((next[0] as u32) << 24)
170 + ((next[1] as u32) << 16)
171 + ((next[2] as u32) << 8)
172 + (next[3] as u32)
173 }
174
175 fn next_u64(&mut self) -> u64 {
176 impls::next_u64_via_u32(self)
177 }
178
179 fn fill_bytes(&mut self, dest: &mut [u8]) {
180 impls::fill_bytes_via_next(self, dest);
181 }
182}