Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Belt-HMAC-rng #5

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open

Belt-HMAC-rng #5

wants to merge 9 commits into from

Conversation

makavity
Copy link

@makavity makavity commented Jan 4, 2024

Hello!
Just implemented rng from STB (Belarus Crypto standard)
https://apmi.bsu.by/assets/files/std/brng-spec25.pdf

@newpavlov

@makavity
Copy link
Author

makavity commented Jan 4, 2024

Benchmark on M1:

test belt_uint32    ... bench:     484,215 ns/iter (+/- 264,490) = 8 MB/s
test belt_uint64    ... bench:     958,108 ns/iter (+/- 32,285) = 8 MB/s
test gen_bytes_belt ... bench: 124,991,829 ns/iter (+/- 41,119,294) = 8 MB/s

Comment on lines 44 to 101
/// Belt-HMAC-HBELT random number generator core.
pub struct BeltHmacRngCore {
r: GenericArray<u8, U32>,
s: GenericArray<u8, U32>,
key: GenericArray<u8, U32>,
}

impl BeltHmacRngCore {
/// Fill the buffer with random data.
pub fn fill(&mut self, dest: &mut [u8]) {
//SAFETY: Key is always present, by default it is filled with zeros
let mut hmac = HmacHbelt::new_from_slice(&self.key).unwrap();
// 𝑌𝑖 ← hmac[ℎ](𝐾, 𝑟 ‖ 𝑆);
hmac.update(&self.r);
hmac.update(&self.s);
let y = hmac.finalize_fixed_reset();
dest[..BUFSIZE].copy_from_slice(&y);

// 𝑟 ← hmac[ℎ](𝐾, 𝑟).
hmac.update(&self.r);
hmac.finalize_into_reset(&mut self.r);
}
}

impl BlockRngCore for BeltHmacRngCore {
type Item = u32;
type Results = [u32; 8];

fn generate(&mut self, results: &mut Self::Results) {
let mut buf = [0u8; BUFSIZE * BLOCKSIZE];
self.fill(&mut buf);
for i in 0..BLOCKSIZE {
results[i] =
u32::from_le_bytes([buf[i * 4], buf[i * 4 + 1], buf[i * 4 + 2], buf[i * 4 + 3]]);
}
}
}

impl SeedableRng for BeltHmacRngCore {
type Seed = GenericArray<u8, U64>;

fn from_seed(seed: Self::Seed) -> Self {
let key = &seed[..BUFSIZE];
let iv = &seed[BUFSIZE..BUFSIZE + BUFSIZE];

let mut hmac = HmacHbelt::new_from_slice(key).unwrap();

// 𝑟 ← hmac[ℎ](𝐾, 𝑆).
hmac.update(iv);
let r = hmac.finalize_fixed_reset();

BeltHmacRngCore {
r,
s: GenericArray::<u8, U32>::clone_from_slice(iv),
key: GenericArray::<u8, U32>::clone_from_slice(key),
}
}
}
Copy link

@nstilt1 nstilt1 Jan 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not know the plans for this CSPRNGs crate, but I can provide you with a little feedback.

Since the BeltHmacRngCore contains some secret data, you might want to have it impl ZeroizeOnDrop.

generate() appears to use 2 buffers—one named buf that is temporary and discarded in memory, and the other being results. One solution for this would be to keep a temporary buffer GenericArray<u8, U32> member of BeltHmacRngCore. It would be a little more ideal if finalize_into_reset() could work with a GenericArray<u32, U8>, but an alternate solution would be to use core::mem::transmute, union, or zerocopy if the duplicate buffer is a concern.

Having hmac as a member of BeltHmacRngCore could improve performance a little by avoiding initialization every time fill/generate is called.

Then the impl SeedableRng for BeltHmacRngCore might need to call .zeroize() on the input seed, or you could make a wrapper Seed type that implements ZeroizeOnDrop when that feature is activated.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the BeltHmacRngCore contains some secret data, you might want to have it impl ZeroizeOnDrop.

Implemented, thank you.

Having hmac as a member of BeltHmacRngCore could improve performance a little by avoiding initialization every time fill/generate is called.

Sure, performance is increased from 9MB/s to 12MB/s.

Then the impl SeedableRng for BeltHmacRngCore might need to call .zeroize() on the input seed, or you could make a wrapper Seed type that implements ZeroizeOnDrop when that feature is activated.

generate() appears to use 2 buffers—one named buf that is temporary and discarded in memory, and the other being results. One solution for this would be to keep a temporary buffer GenericArray<u8, U32> member of BeltHmacRngCore. It would be a little more ideal if finalize_into_reset() could work with a GenericArray<u32, U8>, but an alternate solution would be to use core::mem::transmute, union, or zerocopy if the duplicate buffer is a concern.

Transmute will broke big endian platform. Don't wanna use union, because unsafe. Will check it later, thank you so much for advises.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants