Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions elliptic-curve/src/hash2curve/group_digest.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use super::MapToCurve;
use crate::hash2field::{hash_to_field, ExpandMsg, FromOkm};
use crate::{
hash2field::{hash_to_field, ExpandMsg, FromOkm},
Result,
};
use group::cofactor::CofactorGroup;

/// Adds hashing arbitrary byte sequences to a valid group element
Expand Down Expand Up @@ -34,9 +37,9 @@ pub trait GroupDigest {
/// let pt = ProjectivePoint::hash_from_bytes::<hash2field::ExpandMsgXof<sha3::Shake256>>(b"test data", b"CURVE_XOF:SHAKE-256_SSWU_RO_");
/// ```
///
fn hash_from_bytes<X: ExpandMsg>(msg: &[u8], dst: &'static [u8]) -> Self::Output {
fn hash_from_bytes<X: ExpandMsg>(msg: &[u8], dst: &'static [u8]) -> Result<Self::Output> {
let mut u = [Self::FieldElement::default(), Self::FieldElement::default()];
hash_to_field::<X, _>(msg, dst, &mut u);
hash_to_field::<X, _>(msg, dst, &mut u)?;
Copy link
Contributor

@daxpedda daxpedda Jan 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Theoretically this can't fail if users are only using ExpandMsg specified in the spec and don't implement FromOkm on a curve with an incredibly high number, again, not specified in the spec.

WDYT? Should we unwrap? Personally, for VOPRF and OPAQUE I'm fine with fallible now.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about I merge this PR and you can open a follow-up to play with that?

let q0 = Self::Output::map_to_curve(u[0]);
let q1 = Self::Output::map_to_curve(u[1]);
// Ideally we could add and then clear cofactor once
Expand All @@ -49,7 +52,7 @@ pub trait GroupDigest {
// isogenies are different with curves like k256 and bls12-381.
// This problem doesn't manifest for curves with no isogeny like p256.
// For k256 and p256 clear_cofactor doesn't do anything anyway so it will be a no-op.
q0.clear_cofactor() + q1.clear_cofactor()
Ok(q0.clear_cofactor() + q1.clear_cofactor())
}

/// Computes the encode to curve routine according to
Expand All @@ -60,10 +63,10 @@ pub trait GroupDigest {
/// uniformly random in G: the set of possible outputs of
/// encode_to_curve is only a fraction of the points in G, and some
/// points in this set are more likely to be output than others.
fn encode_from_bytes<X: ExpandMsg>(msg: &[u8], dst: &'static [u8]) -> Self::Output {
fn encode_from_bytes<X: ExpandMsg>(msg: &[u8], dst: &'static [u8]) -> Result<Self::Output> {
let mut u = [Self::FieldElement::default()];
hash_to_field::<X, _>(msg, dst, &mut u);
hash_to_field::<X, _>(msg, dst, &mut u)?;
let q0 = Self::Output::map_to_curve(u[0]);
q0.clear_cofactor()
Ok(q0.clear_cofactor())
}
}
7 changes: 5 additions & 2 deletions elliptic-curve/src/hash2field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ mod expand_msg_xof;
pub use expand_msg::*;
pub use expand_msg_xmd::*;
pub use expand_msg_xof::*;

use crate::Result;
use generic_array::{typenum::Unsigned, ArrayLength, GenericArray};

/// The trait for helping to convert to a scalar
Expand All @@ -18,16 +20,17 @@ pub trait FromOkm {

/// Convert an arbitrary byte sequence according to
/// <https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3>
pub fn hash_to_field<E, T>(data: &[u8], domain: &'static [u8], out: &mut [T])
pub fn hash_to_field<E, T>(data: &[u8], domain: &'static [u8], out: &mut [T]) -> Result<()>
where
E: ExpandMsg,
T: FromOkm + Default,
{
let len_in_bytes = T::Length::to_usize() * out.len();
let mut tmp = GenericArray::<u8, <T as FromOkm>::Length>::default();
let mut expander = E::expand_message(data, domain, len_in_bytes);
let mut expander = E::expand_message(data, domain, len_in_bytes)?;
for o in out.iter_mut() {
expander.fill_bytes(&mut tmp);
*o = T::from_okm(&tmp);
}
Ok(())
}
5 changes: 3 additions & 2 deletions elliptic-curve/src/hash2field/expand_msg.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::Result;
use digest::{Digest, ExtendableOutputDirty, Update, XofReader};
use generic_array::{ArrayLength, GenericArray};

Expand All @@ -7,11 +8,11 @@ const OVERSIZE_DST_SALT: &[u8] = b"H2C-OVERSIZE-DST-";
const MAX_DST_LEN: usize = 255;

/// Trait for types implementing expand_message interface for hash_to_field
pub trait ExpandMsg {
pub trait ExpandMsg: Sized {
/// Expands `msg` to the required number of bytes
/// Returns an expander that can be used to call `read` until enough
/// bytes have been consumed
fn expand_message(msg: &[u8], dst: &'static [u8], len_in_bytes: usize) -> Self;
fn expand_message(msg: &[u8], dst: &'static [u8], len_in_bytes: usize) -> Result<Self>;

/// Fill the array with the expanded bytes
fn fill_bytes(&mut self, okm: &mut [u8]);
Expand Down
22 changes: 14 additions & 8 deletions elliptic-curve/src/hash2field/expand_msg_xmd.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::{Domain, ExpandMsg};
use crate::{Error, Result};
use digest::{
generic_array::{
typenum::{IsLess, IsLessOrEqual, Unsigned, U256},
Expand Down Expand Up @@ -56,15 +57,20 @@ where
impl<HashT> ExpandMsg for ExpandMsgXmd<HashT>
where
HashT: Digest + BlockInput,
HashT::OutputSize: IsLess<U256>,
HashT::OutputSize: IsLessOrEqual<HashT::BlockSize>,
HashT::OutputSize: IsLess<U256> + IsLessOrEqual<HashT::BlockSize>,
{
fn expand_message(msg: &[u8], dst: &'static [u8], len_in_bytes: usize) -> Self {
fn expand_message(msg: &[u8], dst: &'static [u8], len_in_bytes: usize) -> Result<Self> {
if len_in_bytes > 0xFFFF {
return Err(Error);
}

let b_in_bytes = HashT::OutputSize::to_usize();
let ell = (len_in_bytes + b_in_bytes - 1) / b_in_bytes;
// if ell > 255 {
// panic!("ell was too big in expand_message_xmd");
// }

if ell > 255 {
return Err(Error);
}

let domain = Domain::xmd::<HashT>(dst);
let b_0 = HashT::new()
.chain(GenericArray::<u8, HashT::BlockSize>::default())
Expand All @@ -81,14 +87,14 @@ where
.chain([domain.len() as u8])
.finalize();

Self {
Ok(Self {
b_0,
b_vals,
domain,
index: 1,
offset: 0,
ell,
}
})
}

fn fill_bytes(&mut self, okm: &mut [u8]) {
Expand Down
6 changes: 3 additions & 3 deletions elliptic-curve/src/hash2field/expand_msg_xof.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::ExpandMsg;
use crate::hash2field::Domain;
use crate::{hash2field::Domain, Result};
use digest::{ExtendableOutput, ExtendableOutputDirty, Update, XofReader};
use generic_array::typenum::U32;

Expand All @@ -16,15 +16,15 @@ impl<HashT> ExpandMsg for ExpandMsgXof<HashT>
where
HashT: Default + ExtendableOutput + ExtendableOutputDirty + Update,
{
fn expand_message(msg: &[u8], dst: &'static [u8], len_in_bytes: usize) -> Self {
fn expand_message(msg: &[u8], dst: &'static [u8], len_in_bytes: usize) -> Result<Self> {
let domain = Domain::<U32>::xof::<HashT>(dst);
let reader = HashT::default()
.chain(msg)
.chain([(len_in_bytes >> 8) as u8, len_in_bytes as u8])
.chain(domain.data())
.chain([domain.len() as u8])
.finalize_xof();
Self { reader }
Ok(Self { reader })
}

fn fill_bytes(&mut self, okm: &mut [u8]) {
Expand Down