use curve25519_dalek::Scalar;
use rand_core::{
impls::{next_u32_via_fill, next_u64_via_fill},
CryptoRng,
RngCore,
};
use subtle::{ConditionallySelectable, ConstantTimeEq};
use zeroize::Zeroize;
#[derive(Clone, Copy)]
pub(crate) enum OperationTiming {
Constant,
Variable,
}
pub(crate) fn delta(x: u32, y: u32, timing: OperationTiming) -> Scalar {
match timing {
OperationTiming::Constant => {
let mut result = Scalar::ZERO;
result.conditional_assign(&Scalar::ONE, x.ct_eq(&y));
result
},
OperationTiming::Variable => {
if x == y {
Scalar::ONE
} else {
Scalar::ZERO
}
},
}
}
pub(crate) struct NullRng;
impl RngCore for NullRng {
fn fill_bytes(&mut self, dest: &mut [u8]) {
dest.zeroize();
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
self.fill_bytes(dest);
Ok(())
}
fn next_u32(&mut self) -> u32 {
next_u32_via_fill(self)
}
fn next_u64(&mut self) -> u64 {
next_u64_via_fill(self)
}
}
impl CryptoRng for NullRng {}
#[cfg(test)]
mod test {
use curve25519_dalek::Scalar;
use rand_core::RngCore;
use super::{NullRng, OperationTiming};
use crate::util::delta;
#[test]
fn test_delta() {
for timing in [OperationTiming::Constant, OperationTiming::Variable] {
assert_eq!(delta(0, 0, timing), Scalar::ONE);
assert_eq!(delta(1, 1, timing), Scalar::ONE);
assert_eq!(delta(u32::MAX, u32::MAX, timing), Scalar::ONE);
assert_eq!(delta(0, 1, timing), Scalar::ZERO);
assert_eq!(delta(1, 0, timing), Scalar::ZERO);
assert_eq!(delta(u32::MAX, 0, timing), Scalar::ZERO);
}
}
#[test]
fn test_null_rng() {
let mut rng = NullRng;
assert_eq!(rng.next_u32(), 0);
assert_eq!(rng.next_u64(), 0);
const BUFFER_SIZE: usize = 128;
let mut buffer = [1u8; BUFFER_SIZE]; rng.fill_bytes(&mut buffer);
assert_eq!(buffer, [0u8; BUFFER_SIZE]);
let mut buffer = [1u8; BUFFER_SIZE]; rng.try_fill_bytes(&mut buffer).unwrap();
assert_eq!(buffer, [0u8; BUFFER_SIZE]);
}
}