diff --git a/umbral-pre/Cargo.toml b/umbral-pre/Cargo.toml index c3c7ced6..7e1f6bd9 100644 --- a/umbral-pre/Cargo.toml +++ b/umbral-pre/Cargo.toml @@ -11,7 +11,6 @@ categories = ["cryptography", "no-std"] [dependencies] k256 = { version = "0.7", 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 57819338..859bf3ef 100644 --- a/umbral-pre/src/hashing.rs +++ b/umbral-pre/src/hashing.rs @@ -1,51 +1,49 @@ -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, +/// Hashes arbitrary data with the given domain separation tag +/// 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(dst: &[u8], 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(); + // TODO (#35): use the standard method when it is available in RustCrypto. - 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]); + + let dst_len = (dst.len() as u32).to_be_bytes(); + let data_len = (data.len() as u32).to_be_bytes(); // 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(&dst_len); + digest.update(dst); + digest.update(&data_len); + 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; } @@ -94,6 +92,7 @@ impl ScalarDigest { } pub fn finalize(self) -> CurveScalar { + // TODO (#35): use the standard method when it is available in RustCrypto. CurveScalar::from_digest(self.0) } } @@ -143,18 +142,18 @@ 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 dst = b"sdasdasd"; + let p = unsafe_hash_to_point(&dst[..], &data[..]); + let p_same = unsafe_hash_to_point(&dst[..], &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(&dst[..], &data2[..]); assert_ne!(p, p_data2); - let label2 = b"sdasdasds"; - let p_label2 = unsafe_hash_to_point(&data[..], &label2[..]); - assert_ne!(p, p_label2); + let dst2 = b"sdasdasds"; + let p_dst2 = unsafe_hash_to_point(&dst2[..], &data[..]); + assert_ne!(p, p_dst2); } #[test] diff --git a/umbral-pre/src/params.rs b/umbral-pre/src/params.rs index f69c252f..65b6d431 100644 --- a/umbral-pre/src/params.rs +++ b/umbral-pre/src/params.rs @@ -13,15 +13,15 @@ pub struct Parameters { impl Parameters { /// Creates a new parameter object. pub fn new() -> Self { + // Some future-proofing for a scenario where someone uses a different generator. + // We wouldn't want `u` to be the same in that case. 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"POINT_U", &g_bytes).unwrap(); Self { u } }