Skip to content

Commit

Permalink
Merge pull request nucypher#36 from fjarri/hash-removal
Browse files Browse the repository at this point in the history
Hash functions cleanup
  • Loading branch information
fjarri authored Mar 6, 2021
2 parents 9da12a6 + 966e08f commit 125a2c6
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 48 deletions.
2 changes: 0 additions & 2 deletions umbral-pre/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ categories = ["cryptography", "no-std"]

[dependencies]
k256 = { version = "0.7", default-features = false, features = ["ecdsa", "arithmetic"] }
blake2 = "0.9"
sha3 = "0.9"
sha2 = "0.9"
chacha20poly1305 = "0.7"
hkdf = "0.10"
Expand Down
1 change: 0 additions & 1 deletion umbral-pre/src/capsule_frag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,6 @@ impl CapsuleFrag {
let v2 = self.proof.point_v2;
let u2 = self.proof.kfrag_pok;

// TODO (#2): original uses ExtendedKeccak here
let h = ScalarDigest::new()
.chain_points(&[e, e1, e2, v, v1, v2, u, u1, u2])
.chain_scalar(&self.proof.metadata)
Expand Down
6 changes: 3 additions & 3 deletions umbral-pre/src/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ impl SerializableToArray for PublicKey {
#[cfg(test)]
mod tests {

use sha3::Sha3_256;
use sha2::Sha256;
use signature::digest::Digest;

use super::{PublicKey, SecretKey};
Expand All @@ -295,11 +295,11 @@ mod tests {
fn test_sign_and_verify() {
let sk = SecretKey::random();
let message = b"asdafdahsfdasdfasd";
let digest = Sha3_256::new().chain(message);
let digest = Sha256::new().chain(message);
let signature = sk.sign_digest(digest);

let pk = PublicKey::from_secret_key(&sk);
let digest = Sha3_256::new().chain(message);
let digest = Sha256::new().chain(message);
assert!(pk.verify_digest(digest, &signature));
}
}
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
72 changes: 35 additions & 37 deletions umbral-pre/src/hashing.rs
Original file line number Diff line number Diff line change
@@ -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 sha3::Sha3_256;
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<CurvePoint> {
pub fn unsafe_hash_to_point(dst: &[u8], 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();
// TODO (#35): use the standard method when it is available in RustCrypto.

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]);

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 < <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(&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;
}
Expand All @@ -58,12 +56,11 @@ pub fn unsafe_hash_to_point(data: &[u8], label: &[u8]) -> Option<CurvePoint> {
None
}

pub(crate) struct ScalarDigest(Sha3_256);
pub(crate) struct ScalarDigest(Sha256);

// TODO (#2): original uses ExtendedKeccak here
impl ScalarDigest {
pub fn new() -> Self {
Self(Sha3_256::new())
Self(Sha256::new())
}

pub fn new_with_dst(bytes: &[u8]) -> Self {
Expand Down Expand Up @@ -95,15 +92,16 @@ impl ScalarDigest {
}

pub fn finalize(self) -> CurveScalar {
// TODO (#35): use the standard method when it is available in RustCrypto.
CurveScalar::from_digest(self.0)
}
}

pub(crate) struct SignatureDigest(Sha3_256);
pub(crate) struct SignatureDigest(Sha256);

impl SignatureDigest {
pub fn new() -> Self {
Self(Sha3_256::new())
Self(Sha256::new())
}

fn chain_impl(self, bytes: &[u8]) -> Self {
Expand Down Expand Up @@ -144,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]
Expand Down
3 changes: 3 additions & 0 deletions umbral-pre/src/hashing_ds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use crate::curve::{CurvePoint, CurveScalar};
use crate::hashing::ScalarDigest;

// TODO (#39): Ideally this should return a non-zero scalar.
pub(crate) fn hash_to_polynomial_arg(
precursor: &CurvePoint,
pubkey: &CurvePoint,
Expand All @@ -18,6 +19,8 @@ pub(crate) fn hash_to_polynomial_arg(
.finalize()
}

// TODO (#39): Ideally this should return a non-zero scalar.
// (when it does, the loop in `KeyFragFactory::new()` can be removed)
pub(crate) fn hash_to_shared_secret(
precursor: &CurvePoint,
pubkey: &CurvePoint,
Expand Down
6 changes: 3 additions & 3 deletions umbral-pre/src/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
}
Expand Down

0 comments on commit 125a2c6

Please sign in to comment.