-
Notifications
You must be signed in to change notification settings - Fork 88
/
rng.rs
68 lines (61 loc) · 2.07 KB
/
rng.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use crate::Vec;
use algebra_core::{FromBytes, ToBytes};
use core::marker::PhantomData;
use digest::{generic_array::GenericArray, Digest};
use rand_chacha::ChaChaRng;
use rand_core::{RngCore, SeedableRng};
/// A `SeedableRng` that refreshes its seed by hashing together the previous seed
/// and the new seed material.
// TODO: later: re-evaluate decision about ChaChaRng
pub struct FiatShamirRng<D: Digest> {
r: ChaChaRng,
seed: GenericArray<u8, D::OutputSize>,
#[doc(hidden)]
digest: PhantomData<D>,
}
impl<D: Digest> RngCore for FiatShamirRng<D> {
#[inline]
fn next_u32(&mut self) -> u32 {
self.r.next_u32()
}
#[inline]
fn next_u64(&mut self) -> u64 {
self.r.next_u64()
}
#[inline]
fn fill_bytes(&mut self, dest: &mut [u8]) {
self.r.fill_bytes(dest);
}
#[inline]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
Ok(self.r.fill_bytes(dest))
}
}
impl<D: Digest> FiatShamirRng<D> {
/// Create a new `Self` by initializing with a fresh seed.
/// `self.seed = H(self.seed || new_seed)`.
#[inline]
pub fn from_seed<'a, T: 'a + ToBytes>(seed: &'a T) -> Self {
let mut bytes = Vec::new();
seed.write(&mut bytes).expect("failed to convert to bytes");
let seed = D::digest(&bytes);
let r_seed: [u8; 32] = FromBytes::read(seed.as_ref()).expect("failed to get [u32; 8]");
let r = ChaChaRng::from_seed(r_seed);
Self {
r,
seed,
digest: PhantomData,
}
}
/// Refresh `self.seed` with new material. Achieved by setting
/// `self.seed = H(self.seed || new_seed)`.
#[inline]
pub fn absorb<'a, T: 'a + ToBytes>(&mut self, seed: &'a T) {
let mut bytes = Vec::new();
seed.write(&mut bytes).expect("failed to convert to bytes");
bytes.extend_from_slice(&self.seed);
self.seed = D::digest(&bytes);
let seed: [u8; 32] = FromBytes::read(self.seed.as_ref()).expect("failed to get [u32; 8]");
self.r = ChaChaRng::from_seed(seed);
}
}