Skip to content

Commit

Permalink
Get rid of Blake2 and simplify unsafe_hash_to_point()
Browse files Browse the repository at this point in the history
  • Loading branch information
fjarri committed Mar 3, 2021
1 parent 00e4799 commit 44569f0
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 41 deletions.
1 change: 0 additions & 1 deletion umbral-pre/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 2 additions & 2 deletions umbral-pre/src/dem.rs
Original file line number Diff line number Diff line change
@@ -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 = <ChaCha20Poly1305 as NewAead>::KeySize;

fn kdf(seed: &[u8], salt: Option<&[u8]>, info: Option<&[u8]>) -> GenericArray<u8, KdfSize> {
let hk = Hkdf::<Blake2b>::new(salt, &seed);
let hk = Hkdf::<Sha256>::new(salt, &seed);

let mut okm = GenericArray::<u8, KdfSize>::default();

Expand Down
48 changes: 16 additions & 32 deletions umbral-pre/src/hashing.rs
Original file line number Diff line number Diff line change
@@ -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<CurvePoint> {
pub fn unsafe_hash_to_point(data: &[u8]) -> Option<CurvePoint> {
// 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 = <CurvePoint as SerializableToArray>::Size;
let point_size = PointSize::to_usize();
let mut arr = GenericArray::<u8, PointSize>::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::<u8, U1>::from_slice(&[2u8]);

// We use an internal 32-bit counter as additional input
let mut i = 0u32;
while i < <u32>::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::<u8, PointSize>::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;
}
Expand Down Expand Up @@ -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]
Expand Down
7 changes: 1 addition & 6 deletions umbral-pre/src/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
}
Expand Down

0 comments on commit 44569f0

Please sign in to comment.