Remove allocations by serialize (#29)
* Changed `expand_message_xmd` input to `Iterator` * Changed `hash_to_scalar` input to `Iterator` * Fix rustfmt * Add documentation for private helper types * Fix documentation * Improve `chain!()` syntax bias * Move helper functions to `mod util`
This commit is contained in:
+25
-16
@@ -6,7 +6,7 @@
|
||||
// of this source tree.
|
||||
|
||||
use crate::errors::InternalError;
|
||||
use crate::serialization::i2osp;
|
||||
use crate::util::i2osp;
|
||||
use core::ops::Add;
|
||||
use digest::{BlockInput, Digest};
|
||||
use generic_array::{
|
||||
@@ -28,11 +28,13 @@ fn xor<L: ArrayLength<u8>>(x: GenericArray<u8, L>, y: GenericArray<u8, L>) -> Ge
|
||||
/// Corresponds to the expand_message_xmd() function defined in
|
||||
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-10.txt>
|
||||
pub fn expand_message_xmd<
|
||||
'a,
|
||||
H: BlockInput + Digest,
|
||||
L: ArrayLength<u8>,
|
||||
M: IntoIterator<Item = &'a [u8]>,
|
||||
D: ArrayLength<u8> + Add<U1>,
|
||||
>(
|
||||
msg: &[u8],
|
||||
msg: M,
|
||||
dst: GenericArray<u8, D>,
|
||||
) -> Result<GenericArray<u8, L>, InternalError>
|
||||
where
|
||||
@@ -46,19 +48,20 @@ where
|
||||
let dst_prime = dst.concat(i2osp::<U1>(D::USIZE)?);
|
||||
let z_pad = i2osp::<<H as BlockInput>::BlockSize>(0)?;
|
||||
let l_i_b_str = i2osp::<U2>(L::USIZE)?;
|
||||
let msg_0 = i2osp::<U1>(0)?;
|
||||
let msg_prime =
|
||||
core::array::IntoIter::new([z_pad.as_slice(), msg, &l_i_b_str, &msg_0, &dst_prime]);
|
||||
|
||||
let mut h = H::new();
|
||||
|
||||
// msg_prime = Z_pad || msg || l_i_b_str || I2OSP(0, 1) || DST_prime
|
||||
h.update(z_pad);
|
||||
for bytes in msg {
|
||||
h.update(bytes)
|
||||
}
|
||||
h.update(l_i_b_str);
|
||||
h.update(i2osp::<U1>(0)?);
|
||||
h.update(&dst_prime);
|
||||
|
||||
// b[0]
|
||||
let b_0 = msg_prime
|
||||
.into_iter()
|
||||
.fold(&mut h, |h, msg| {
|
||||
h.update(msg);
|
||||
h
|
||||
})
|
||||
.finalize_reset();
|
||||
let b_0 = h.finalize_reset();
|
||||
let mut b_i = GenericArray::default();
|
||||
|
||||
let mut uniform_bytes = GenericArray::default();
|
||||
@@ -192,10 +195,16 @@ mod tests {
|
||||
|
||||
for tv in test_vectors {
|
||||
let uniform_bytes = match tv.len_in_bytes {
|
||||
32 => super::expand_message_xmd::<sha2::Sha256, U32, _>(tv.msg.as_bytes(), dst)
|
||||
.map(|bytes| bytes.to_vec()),
|
||||
128 => super::expand_message_xmd::<sha2::Sha256, U128, _>(tv.msg.as_bytes(), dst)
|
||||
.map(|bytes| bytes.to_vec()),
|
||||
32 => super::expand_message_xmd::<sha2::Sha256, U32, _, _>(
|
||||
Some(tv.msg.as_bytes()),
|
||||
dst,
|
||||
)
|
||||
.map(|bytes| bytes.to_vec()),
|
||||
128 => super::expand_message_xmd::<sha2::Sha256, U128, _, _>(
|
||||
Some(tv.msg.as_bytes()),
|
||||
dst,
|
||||
)
|
||||
.map(|bytes| bytes.to_vec()),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
.unwrap();
|
||||
|
||||
+7
-2
@@ -57,8 +57,13 @@ pub trait Group:
|
||||
<D as Add<U1>>::Output: ArrayLength<u8>;
|
||||
|
||||
/// Hashes a slice of pseudo-random bytes to a scalar
|
||||
fn hash_to_scalar<H: BlockInput + Digest, D: ArrayLength<u8> + Add<U1>>(
|
||||
input: &[u8],
|
||||
fn hash_to_scalar<
|
||||
'a,
|
||||
H: BlockInput + Digest,
|
||||
D: ArrayLength<u8> + Add<U1>,
|
||||
I: IntoIterator<Item = &'a [u8]>,
|
||||
>(
|
||||
input: I,
|
||||
dst: GenericArray<u8, D>,
|
||||
) -> Result<Self::Scalar, InternalError>
|
||||
where
|
||||
|
||||
+16
-10
@@ -75,7 +75,7 @@ impl Group for ProjectivePoint {
|
||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3
|
||||
// `hash_to_field` calls `expand_message` with a `len_in_bytes` of `count * L`
|
||||
let uniform_bytes =
|
||||
super::expand::expand_message_xmd::<H, <L as Mul<U2>>::Output, _>(msg, dst)?;
|
||||
super::expand::expand_message_xmd::<H, <L as Mul<U2>>::Output, _, _>(Some(msg), dst)?;
|
||||
|
||||
// hash to curve
|
||||
let (q0x, q0y) = hash_to_curve_simple_swu(&uniform_bytes[..L::USIZE], &A, &B, &P, &Z);
|
||||
@@ -97,8 +97,13 @@ impl Group for ProjectivePoint {
|
||||
|
||||
// Implements the `HashToScalar()` function from
|
||||
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-07.html#section-4.3
|
||||
fn hash_to_scalar<H: BlockInput + Digest, D: ArrayLength<u8> + Add<U1>>(
|
||||
input: &[u8],
|
||||
fn hash_to_scalar<
|
||||
'a,
|
||||
H: BlockInput + Digest,
|
||||
D: ArrayLength<u8> + Add<U1>,
|
||||
I: IntoIterator<Item = &'a [u8]>,
|
||||
>(
|
||||
input: I,
|
||||
dst: GenericArray<u8, D>,
|
||||
) -> Result<Self::Scalar, InternalError>
|
||||
where
|
||||
@@ -115,7 +120,7 @@ impl Group for ProjectivePoint {
|
||||
|
||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3
|
||||
// `HashToScalar` is `hash_to_field`
|
||||
let uniform_bytes = super::expand::expand_message_xmd::<H, L, _>(input, dst)?;
|
||||
let uniform_bytes = super::expand::expand_message_xmd::<H, L, _, _>(input, dst)?;
|
||||
let bytes = BigInt::from_bytes_be(Sign::Plus, &uniform_bytes)
|
||||
.mod_floor(&N)
|
||||
.to_bytes_be()
|
||||
@@ -180,7 +185,7 @@ impl Group for ProjectivePoint {
|
||||
///
|
||||
/// `cmov`, `mod_floor` and `modpow` needs to be made constant-time, which
|
||||
/// will be supported after crypto-bigint is no longer experimental. See
|
||||
/// https://github.com/novifinancial/voprf/issues/13 for more context.
|
||||
/// <https://github.com/novifinancial/voprf/issues/13> for more context.
|
||||
|
||||
#[allow(clippy::many_single_char_names)]
|
||||
fn hash_to_curve_simple_swu<N: ArrayLength<u8>>(
|
||||
@@ -536,11 +541,12 @@ mod tests {
|
||||
let dst = GenericArray::from(*b"QUUX-V01-CS02-with-P256_XMD:SHA-256_SSWU_RO_");
|
||||
|
||||
for tv in test_vectors {
|
||||
let uniform_bytes = super::super::expand::expand_message_xmd::<sha2::Sha256, U96, _>(
|
||||
tv.msg.as_bytes(),
|
||||
dst,
|
||||
)
|
||||
.unwrap();
|
||||
let uniform_bytes =
|
||||
super::super::expand::expand_message_xmd::<sha2::Sha256, U96, _, _>(
|
||||
Some(tv.msg.as_bytes()),
|
||||
dst,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let u0 = BigInt::from_bytes_be(Sign::Plus, &uniform_bytes[..48]).mod_floor(&P);
|
||||
let u1 = BigInt::from_bytes_be(Sign::Plus, &uniform_bytes[48..]).mod_floor(&P);
|
||||
|
||||
@@ -42,7 +42,7 @@ impl Group for RistrettoPoint {
|
||||
where
|
||||
<D as Add<U1>>::Output: ArrayLength<u8>,
|
||||
{
|
||||
let uniform_bytes = super::expand::expand_message_xmd::<H, U64, _>(msg, dst)?;
|
||||
let uniform_bytes = super::expand::expand_message_xmd::<H, U64, _, _>(Some(msg), dst)?;
|
||||
|
||||
Ok(RistrettoPoint::from_uniform_bytes(
|
||||
uniform_bytes
|
||||
@@ -54,14 +54,19 @@ impl Group for RistrettoPoint {
|
||||
|
||||
// Implements the `HashToScalar()` function from
|
||||
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-07.html#section-4.1
|
||||
fn hash_to_scalar<H: BlockInput + Digest, D: ArrayLength<u8> + Add<U1>>(
|
||||
input: &[u8],
|
||||
fn hash_to_scalar<
|
||||
'a,
|
||||
H: BlockInput + Digest,
|
||||
D: ArrayLength<u8> + Add<U1>,
|
||||
I: IntoIterator<Item = &'a [u8]>,
|
||||
>(
|
||||
input: I,
|
||||
dst: GenericArray<u8, D>,
|
||||
) -> Result<Self::Scalar, InternalError>
|
||||
where
|
||||
<D as Add<U1>>::Output: ArrayLength<u8>,
|
||||
{
|
||||
let uniform_bytes = super::expand::expand_message_xmd::<H, U64, _>(input, dst)?;
|
||||
let uniform_bytes = super::expand::expand_message_xmd::<H, U64, _, _>(input, dst)?;
|
||||
|
||||
Ok(Scalar::from_bytes_mod_order_wide(
|
||||
uniform_bytes
|
||||
|
||||
Reference in New Issue
Block a user