From d019da1ee0409b5c680052ece60ee51b91c53b4c Mon Sep 17 00:00:00 2001 From: Bogdan Opanchuk Date: Tue, 2 Mar 2021 21:24:45 -0800 Subject: [PATCH] Get rid of Blake2 and simplify unsafe_hash_to_point() --- umbral-pre/Cargo.toml | 1 - umbral-pre/src/dem.rs | 4 ++-- umbral-pre/src/hashing.rs | 48 +++++++++++++-------------------------- umbral-pre/src/params.rs | 7 +----- 4 files changed, 19 insertions(+), 41 deletions(-) diff --git a/umbral-pre/Cargo.toml b/umbral-pre/Cargo.toml index 31fd04b6..7f9a6412 100644 --- a/umbral-pre/Cargo.toml +++ b/umbral-pre/Cargo.toml @@ -11,7 +11,6 @@ categories = ["cryptography", "no-std"] [dependencies] k256 = { version = "0.6", default-features = false, features = ["ecdsa", "arithmetic"] } -blake2 = "0.9" sha2 = "0.9" chacha20poly1305 = "0.7" hkdf = "0.10" diff --git a/umbral-pre/src/dem.rs b/umbral-pre/src/dem.rs index 777c20a0..2570ca35 100644 --- a/umbral-pre/src/dem.rs +++ b/umbral-pre/src/dem.rs @@ -1,18 +1,18 @@ use alloc::boxed::Box; use aead::{Aead, AeadInPlace, Payload}; -use blake2::Blake2b; use chacha20poly1305::aead::NewAead; use chacha20poly1305::{ChaCha20Poly1305, Key, Nonce}; use generic_array::{typenum::Unsigned, GenericArray}; use hkdf::Hkdf; use rand_core::OsRng; use rand_core::RngCore; +use sha2::Sha256; type KdfSize = ::KeySize; fn kdf(seed: &[u8], salt: Option<&[u8]>, info: Option<&[u8]>) -> GenericArray { - let hk = Hkdf::::new(salt, &seed); + let hk = Hkdf::::new(salt, &seed); let mut okm = GenericArray::::default(); diff --git a/umbral-pre/src/hashing.rs b/umbral-pre/src/hashing.rs index 72899617..b9e48ac9 100644 --- a/umbral-pre/src/hashing.rs +++ b/umbral-pre/src/hashing.rs @@ -1,51 +1,40 @@ -use blake2::VarBlake2b; -use digest::{Digest, Update, VariableOutput}; -use generic_array::typenum::Unsigned; +use digest::Digest; +use generic_array::sequence::Concat; use generic_array::GenericArray; use sha2::Sha256; +use typenum::U1; use crate::curve::{CurvePoint, CurveScalar, PublicKey, SecretKey, Signature}; use crate::traits::SerializableToArray; /// Hashes arbitrary data into a valid EC point of the specified curve, /// using the try-and-increment method. -/// It admits an optional label as an additional input to the hash function. -/// It uses BLAKE2b (with a digest size of 64 bytes) as the internal hash function. /// /// WARNING: Do not use when the input data is secret, as this implementation is not /// in constant time, and hence, it is not safe with respect to timing attacks. -pub fn unsafe_hash_to_point(data: &[u8], label: &[u8]) -> Option { +pub fn unsafe_hash_to_point(data: &[u8]) -> Option { // NOTE: Yes, this function is hacky, but it is the only way // to hash to a point with an *unknown* discrete log. // Don't replace with hashing to scalar and multiplying by a generator! - let len_data = (data.len() as u32).to_be_bytes(); - let len_label = (label.len() as u32).to_be_bytes(); - - type PointSize = ::Size; - let point_size = PointSize::to_usize(); - let mut arr = GenericArray::::default(); + // Fixed sign prefix. Halves the range of the generated points, but we only need one, + // and it is always the same. + let sign_prefix = GenericArray::::from_slice(&[2u8]); // We use an internal 32-bit counter as additional input let mut i = 0u32; while i < ::MAX { let ibytes = (i as u32).to_be_bytes(); - // May fail if `point_size` is too large for the hashing algorithm. - let digest = VarBlake2b::new(point_size).ok()?; - digest - .chain(&len_label) - .chain(label) - .chain(&len_data) - .chain(data) - .chain(&ibytes) - .finalize_variable(|buf| arr = *GenericArray::::from_slice(buf)); + let mut digest = Sha256::new(); + digest.update(data); + digest.update(&ibytes); + let result = digest.finalize(); // Set the sign byte - let arr_data = arr.as_mut_slice(); - arr_data[0] = if arr_data[0] & 1 == 0 { 2 } else { 3 }; + let maybe_point_bytes = sign_prefix.concat(result); - let maybe_point = CurvePoint::from_bytes(&arr); + let maybe_point = CurvePoint::from_bytes(&maybe_point_bytes); if maybe_point.is_some() { return maybe_point; } @@ -140,18 +129,13 @@ mod tests { #[test] fn test_unsafe_hash_to_point() { let data = b"abcdefg"; - let label = b"sdasdasd"; - let p = unsafe_hash_to_point(&data[..], &label[..]); - let p_same = unsafe_hash_to_point(&data[..], &label[..]); + let p = unsafe_hash_to_point(&data[..]); + let p_same = unsafe_hash_to_point(&data[..]); assert_eq!(p, p_same); let data2 = b"abcdefgh"; - let p_data2 = unsafe_hash_to_point(&data2[..], &label[..]); + let p_data2 = unsafe_hash_to_point(&data2[..]); assert_ne!(p, p_data2); - - let label2 = b"sdasdasds"; - let p_label2 = unsafe_hash_to_point(&data[..], &label2[..]); - assert_ne!(p, p_label2); } #[test] diff --git a/umbral-pre/src/params.rs b/umbral-pre/src/params.rs index f69c252f..67b6f929 100644 --- a/umbral-pre/src/params.rs +++ b/umbral-pre/src/params.rs @@ -13,15 +13,10 @@ pub struct Parameters { impl Parameters { /// Creates a new parameter object. pub fn new() -> Self { - let g = CurvePoint::generator(); - let g_bytes = g.to_array(); - - let parameters_seed = b"NuCypher/UmbralParameters/u"; - // Only fails with a minuscule probability, // or if the size of a point is too large for the hasher. // In any case, we will notice it in tests. - let u = unsafe_hash_to_point(&g_bytes, parameters_seed).unwrap(); + let u = unsafe_hash_to_point(b"NuCypher/UmbralParameters/u").unwrap(); Self { u } }