Skip to content
Open
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 1 addition & 7 deletions ed448-goldilocks/src/decaf/points.rs
Original file line number Diff line number Diff line change
Expand Up @@ -599,8 +599,6 @@ impl From<NonIdentity<DecafPoint>> for DecafPoint {
mod test {
use super::*;
use crate::TWISTED_EDWARDS_BASE_POINT;
use hash2curve::ExpandMsgXof;
use sha3::Shake256;

#[test]
fn test_edwards_decaf_operations() {
Expand Down Expand Up @@ -751,11 +749,7 @@ mod test {
#[test]
fn test_hash_to_curve() {
let msg = b"Hello, world!";
let point = hash2curve::hash_from_bytes::<Decaf448, ExpandMsgXof<Shake256>>(
&[msg],
&[b"test_hash_to_curve"],
)
.unwrap();
let point = Decaf448::hash_from_bytes(msg, b"test_hash_to_curve").unwrap();
assert_eq!(point.0.is_on_curve().unwrap_u8(), 1u8);
assert_ne!(point, DecafPoint::IDENTITY);
assert_ne!(point, DecafPoint::GENERATOR);
Expand Down
10 changes: 2 additions & 8 deletions ed448-goldilocks/src/edwards/extended.rs
Original file line number Diff line number Diff line change
Expand Up @@ -946,9 +946,7 @@ mod tests {
];

for (msg, x, y) in MSGS {
let p =
hash2curve::hash_from_bytes::<Ed448, ExpandMsgXof<sha3::Shake256>>(&[msg], &[DST])
.unwrap();
let p = Ed448::hash_from_bytes(msg, DST).unwrap();
assert_eq!(p.is_on_curve().unwrap_u8(), 1u8);
let p = p.to_affine();
let mut xx = [0u8; 56];
Expand Down Expand Up @@ -985,11 +983,7 @@ mod tests {
];

for (msg, x, y) in MSGS {
let p = hash2curve::encode_from_bytes::<Ed448, ExpandMsgXof<sha3::Shake256>>(
&[msg],
&[DST],
)
.unwrap();
let p = Ed448::encode_from_bytes(msg, DST).unwrap();
assert_eq!(p.is_on_curve().unwrap_u8(), 1u8);
let p = p.to_affine();
let mut xx = [0u8; 56];
Expand Down
1 change: 1 addition & 0 deletions ed448-goldilocks/src/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod element;
mod scalar;

pub(crate) use element::*;
pub use element::{Decaf448Map, Elligator2};
pub(crate) use scalar::CurveWithScalar;
pub use scalar::{MODULUS_LIMBS, ORDER, Scalar, ScalarBytes, WIDE_ORDER, WideScalarBytes};

Expand Down
18 changes: 9 additions & 9 deletions ed448-goldilocks/src/field/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use elliptic_curve::{
array::Array,
bigint::{
Integer, NonZero, U448, U704, Zero,
consts::{U28, U56, U84, U88},
consts::{U56, U84, U88},
modular::ConstMontyParams,
},
zeroize::DefaultIsZeroes,
Expand Down Expand Up @@ -190,21 +190,21 @@ impl Neg for FieldElement {
}
}

impl MapToCurve for Ed448 {
type SecurityLevel = U28;
type FieldElement = FieldElement;
type Length = U84;
/// Elligator2 mapping for [`Ed448`] hash-to-curve operations.
#[derive(Clone, Copy, Debug)]
pub struct Elligator2;

impl MapToCurve<Ed448> for Elligator2 {
fn map_to_curve(element: FieldElement) -> EdwardsPoint {
element.map_to_curve_elligator2().isogeny().to_edwards()
}
}

impl MapToCurve for Decaf448 {
type SecurityLevel = U28;
type FieldElement = FieldElement;
type Length = U56;
/// [`Decaf448`] mapping for hash-to-curve operations.
#[derive(Clone, Copy, Debug)]
pub struct Decaf448Map;

impl MapToCurve<Decaf448> for Decaf448Map {
fn map_to_curve(element: FieldElement) -> DecafPoint {
DecafPoint(element.map_to_curve_decaf448())
}
Expand Down
22 changes: 18 additions & 4 deletions ed448-goldilocks/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub(crate) mod montgomery;
#[cfg(feature = "signing")]
pub(crate) mod sign;

pub(crate) use field::{GOLDILOCKS_BASE_POINT, TWISTED_EDWARDS_BASE_POINT};
pub(crate) use field::{FieldElement, GOLDILOCKS_BASE_POINT, TWISTED_EDWARDS_BASE_POINT};

pub use decaf::{
AffinePoint as DecafAffinePoint, CompressedDecaf, DecafPoint, DecafScalar, DecafScalarBytes,
Expand All @@ -57,18 +57,18 @@ pub use edwards::{
AffinePoint, CompressedEdwardsY, EdwardsPoint, EdwardsScalar, EdwardsScalarBytes,
WideEdwardsScalarBytes,
};
pub use field::{MODULUS_LIMBS, ORDER, Scalar, WIDE_ORDER};
pub use field::{Decaf448Map, Elligator2, MODULUS_LIMBS, ORDER, Scalar, WIDE_ORDER};
pub use montgomery::{MontgomeryPoint, ProjectiveMontgomeryPoint};
#[cfg(feature = "signing")]
pub use sign::*;

use elliptic_curve::{
Curve, FieldBytesEncoding, PrimeCurve,
array::typenum::{U56, U57},
array::typenum::{U28, U56, U57, U84},
bigint::{ArrayEncoding, Odd, U448},
point::PointCompression,
};
use hash2curve::{ExpandMsgXof, GroupDigest};
use hash2curve::{ExpandMsgXof, GroupDigest, HashToCurve};
use sha3::Shake256;

/// Edwards448 curve.
Expand Down Expand Up @@ -116,11 +116,18 @@ impl elliptic_curve::CurveArithmetic for Ed448 {
type Scalar = EdwardsScalar;
}

impl HashToCurve for Ed448 {
type SecurityLevel = U28;
type FieldElement = FieldElement;
type Length = U84;
}

impl GroupDigest for Ed448 {
const HASH_TO_CURVE_ID: &[u8] = b"edwards448_XOF:SHAKE256_ELL2_RO_";
const ENCODE_TO_CURVE_ID: &[u8] = b"edwards448_XOF:SHAKE256_ELL2_NU_";

type ExpandMsg = ExpandMsgXof<Shake256>;
type MapToCurve = Elligator2;
}

/// Decaf448 curve.
Expand Down Expand Up @@ -168,9 +175,16 @@ impl elliptic_curve::CurveArithmetic for Decaf448 {
type Scalar = DecafScalar;
}

impl HashToCurve for Decaf448 {
type SecurityLevel = U28;
type FieldElement = FieldElement;
type Length = U56;
}

impl GroupDigest for Decaf448 {
const HASH_TO_CURVE_ID: &[u8] = b"decaf448_XOF:SHAKE256_D448MAP_RO_";
const ENCODE_TO_CURVE_ID: &[u8] = b"decaf448_XOF:SHAKE256_D448MAP_NU_";

type ExpandMsg = ExpandMsgXof<Shake256>;
type MapToCurve = Decaf448Map;
}
85 changes: 6 additions & 79 deletions hash2curve/src/group_digest.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
//! Traits for handling hash to curve.

use super::{ExpandMsg, MapToCurve, hash_to_field};
use crate::{ExpandMsg, HashToCurve, MapToCurve};
use elliptic_curve::ProjectivePoint;
use elliptic_curve::array::typenum::NonZero;
use elliptic_curve::array::{Array, ArraySize};
use elliptic_curve::group::cofactor::CofactorGroup;
use elliptic_curve::ops::Reduce;

/// Hash arbitrary byte sequences to a valid group element.
pub trait GroupDigest: MapToCurve {
pub trait GroupDigest: HashToCurve {
/// Suite ID for the [hash to curve routine](Self::hash_from_bytes).
const HASH_TO_CURVE_ID: &[u8];
/// Suite ID for the [encode to curve routine](Self::encode_from_bytes).
const ENCODE_TO_CURVE_ID: &[u8];

/// The `expand_message` function to use.
type ExpandMsg: ExpandMsg<Self::SecurityLevel>;
/// The mapping function.
type MapToCurve: MapToCurve<Self>;

/// Computes the hash to curve routine.
///
Expand All @@ -40,7 +38,7 @@ pub trait GroupDigest: MapToCurve {
dst: &[u8],
) -> Result<ProjectivePoint<Self>, <Self::ExpandMsg as ExpandMsg<Self::SecurityLevel>>::Error>
{
hash_from_bytes::<Self, Self::ExpandMsg>(&[msg], &[dst])
crate::hash_from_bytes::<Self, Self::ExpandMsg, Self::MapToCurve>(&[msg], &[dst])
}

/// Computes the encode to curve routine.
Expand All @@ -65,77 +63,6 @@ pub trait GroupDigest: MapToCurve {
dst: &[u8],
) -> Result<ProjectivePoint<Self>, <Self::ExpandMsg as ExpandMsg<Self::SecurityLevel>>::Error>
{
encode_from_bytes::<Self, Self::ExpandMsg>(&[msg], &[dst])
crate::encode_from_bytes::<Self, Self::ExpandMsg, Self::MapToCurve>(&[msg], &[dst])
}
}

/// Computes the hash to curve routine.
/// See [`GroupDigest::hash_from_bytes()`] for more details.
///
/// For the `expand_message` call, `len_in_bytes = <Self::FieldElement as FromOkm>::Length * 2`.
/// This value must be less than `u16::MAX` or otherwise a compiler error will occur.
///
/// # Errors
///
/// When the chosen [`ExpandMsg`] implementation returns an error. See [`ExpandMsgXmdError`]
/// and [`ExpandMsgXofError`] for examples.
///
/// [`ExpandMsgXmdError`]: crate::ExpandMsgXmdError
/// [`ExpandMsgXofError`]: crate::ExpandMsgXofError
pub fn hash_from_bytes<C, X>(msg: &[&[u8]], dst: &[&[u8]]) -> Result<ProjectivePoint<C>, X::Error>
where
C: MapToCurve,
X: ExpandMsg<C::SecurityLevel>,
{
let [u0, u1] = hash_to_field::<2, X, _, C::FieldElement, C::Length>(msg, dst)?;
let q0 = C::map_to_curve(u0);
let q1 = C::map_to_curve(u1);
Ok((q0 + q1).clear_cofactor())
}

/// Computes the encode to curve routine.
/// See [`GroupDigest::encode_from_bytes()`] for more details.
///
/// For the `expand_message` call, `len_in_bytes = <Self::FieldElement as FromOkm>::Length`.
///
/// # Errors
///
/// When the chosen [`ExpandMsg`] implementation returns an error. See [`ExpandMsgXmdError`]
/// and [`ExpandMsgXofError`] for examples.
///
/// [`ExpandMsgXmdError`]: crate::ExpandMsgXmdError
/// [`ExpandMsgXofError`]: crate::ExpandMsgXofError
pub fn encode_from_bytes<C, X>(msg: &[&[u8]], dst: &[&[u8]]) -> Result<ProjectivePoint<C>, X::Error>
where
C: MapToCurve,
X: ExpandMsg<C::SecurityLevel>,
{
let [u] = hash_to_field::<1, X, _, C::FieldElement, C::Length>(msg, dst)?;
let q0 = C::map_to_curve(u);
Ok(q0.clear_cofactor())
}

/// Computes the hash to field routine according to
/// <https://www.rfc-editor.org/rfc/rfc9380.html#section-5-4>
/// and returns a scalar.
///
/// For the `expand_message` call, `len_in_bytes = <Self::FieldElement as FromOkm>::Length`.
/// This value must be less than `u16::MAX` or otherwise a compiler error will occur.
///
/// # Errors
///
/// When the chosen [`ExpandMsg`] implementation returns an error. See [`ExpandMsgXmdError`]
/// and [`ExpandMsgXofError`] for examples.
///
/// [`ExpandMsgXmdError`]: crate::ExpandMsgXmdError
/// [`ExpandMsgXofError`]: crate::ExpandMsgXofError
pub fn hash_to_scalar<C, X, L>(msg: &[&[u8]], dst: &[&[u8]]) -> Result<C::Scalar, X::Error>
where
C: MapToCurve,
X: ExpandMsg<C::SecurityLevel>,
L: ArraySize + NonZero,
C::Scalar: Reduce<Array<u8, L>>,
{
let [u] = hash_to_field::<1, X, _, C::Scalar, L>(msg, dst)?;
Ok(u)
}
87 changes: 87 additions & 0 deletions hash2curve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,95 @@ mod group_digest;
mod hash2field;
mod map2curve;
mod oprf;
mod parameters;

pub use group_digest::*;
pub use hash2field::*;
pub use map2curve::*;
pub use oprf::*;
pub use parameters::*;

use elliptic_curve::ProjectivePoint;
use elliptic_curve::array::typenum::NonZero;
use elliptic_curve::array::{Array, ArraySize};
use elliptic_curve::group::cofactor::CofactorGroup;
use elliptic_curve::ops::Reduce;

/// Computes the hash to curve routine.
/// See [`GroupDigest::hash_from_bytes()`] for more details.
///
/// For the `expand_message` call, `len_in_bytes = <Self::FieldElement as FromOkm>::Length * 2`.
/// This value must be less than `u16::MAX` or otherwise a compiler error will occur.
///
/// # Errors
///
/// When the chosen [`ExpandMsg`] implementation returns an error. See [`ExpandMsgXmdError`]
/// and [`ExpandMsgXofError`] for examples.
///
/// [`ExpandMsgXmdError`]: crate::ExpandMsgXmdError
/// [`ExpandMsgXofError`]: crate::ExpandMsgXofError
pub fn hash_from_bytes<C, X, M>(
msg: &[&[u8]],
dst: &[&[u8]],
) -> Result<ProjectivePoint<C>, X::Error>
where
C: HashToCurve,
X: ExpandMsg<C::SecurityLevel>,
M: MapToCurve<C>,
{
let [u0, u1] = hash_to_field::<2, X, _, C::FieldElement, C::Length>(msg, dst)?;
let q0 = M::map_to_curve(u0);
let q1 = M::map_to_curve(u1);
Ok((q0 + q1).clear_cofactor())
}

/// Computes the encode to curve routine.
/// See [`GroupDigest::encode_from_bytes()`] for more details.
///
/// For the `expand_message` call, `len_in_bytes = <Self::FieldElement as FromOkm>::Length`.
///
/// # Errors
///
/// When the chosen [`ExpandMsg`] implementation returns an error. See [`ExpandMsgXmdError`]
/// and [`ExpandMsgXofError`] for examples.
///
/// [`ExpandMsgXmdError`]: crate::ExpandMsgXmdError
/// [`ExpandMsgXofError`]: crate::ExpandMsgXofError
pub fn encode_from_bytes<C, X, M>(
msg: &[&[u8]],
dst: &[&[u8]],
) -> Result<ProjectivePoint<C>, X::Error>
where
C: HashToCurve,
X: ExpandMsg<C::SecurityLevel>,
M: MapToCurve<C>,
{
let [u] = hash_to_field::<1, X, _, C::FieldElement, C::Length>(msg, dst)?;
let q0 = M::map_to_curve(u);
Ok(q0.clear_cofactor())
}

/// Computes the hash to field routine according to
/// <https://www.rfc-editor.org/rfc/rfc9380.html#section-5-4>
/// and returns a scalar.
///
/// For the `expand_message` call, `len_in_bytes = <Self::FieldElement as FromOkm>::Length`.
/// This value must be less than `u16::MAX` or otherwise a compiler error will occur.
///
/// # Errors
///
/// When the chosen [`ExpandMsg`] implementation returns an error. See [`ExpandMsgXmdError`]
/// and [`ExpandMsgXofError`] for examples.
///
/// [`ExpandMsgXmdError`]: crate::ExpandMsgXmdError
/// [`ExpandMsgXofError`]: crate::ExpandMsgXofError
pub fn hash_to_scalar<C, X, L>(msg: &[&[u8]], dst: &[&[u8]]) -> Result<C::Scalar, X::Error>
where
C: HashToCurve,
X: ExpandMsg<C::SecurityLevel>,
L: ArraySize + NonZero,
C::Scalar: Reduce<Array<u8, L>>,
{
let [u] = hash_to_field::<1, X, _, C::Scalar, L>(msg, dst)?;
Ok(u)
}
Loading