@@ -21,7 +21,7 @@ use rand_core::{CryptoRng, RngCore};
|
||||
use super::Group;
|
||||
use crate::group::{STR_HASH_TO_GROUP, STR_HASH_TO_SCALAR};
|
||||
use crate::voprf::{self, Mode};
|
||||
use crate::{CipherSuite, Error, Result};
|
||||
use crate::{CipherSuite, Error, InternalError, Result};
|
||||
|
||||
impl<C> Group for C
|
||||
where
|
||||
@@ -41,7 +41,10 @@ where
|
||||
|
||||
// Implements the `hash_to_curve()` function from
|
||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3
|
||||
fn hash_to_curve<CS: CipherSuite>(msg: &[&[u8]], mode: Mode) -> Result<Self::Elem>
|
||||
fn hash_to_curve<CS: CipherSuite>(
|
||||
input: &[&[u8]],
|
||||
mode: Mode,
|
||||
) -> Result<Self::Elem, InternalError>
|
||||
where
|
||||
<CS::Hash as OutputSizeUser>::OutputSize:
|
||||
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
||||
@@ -49,11 +52,15 @@ where
|
||||
let dst =
|
||||
GenericArray::from(STR_HASH_TO_GROUP).concat(voprf::get_context_string::<CS>(mode));
|
||||
|
||||
Self::hash_from_bytes::<ExpandMsgXmd<CS::Hash>>(msg, &dst).map_err(|_| Error::PointError)
|
||||
Self::hash_from_bytes::<ExpandMsgXmd<CS::Hash>>(input, &dst)
|
||||
.map_err(|_| InternalError::Input)
|
||||
}
|
||||
|
||||
// Implements the `HashToScalar()` function
|
||||
fn hash_to_scalar<CS: CipherSuite>(input: &[&[u8]], mode: Mode) -> Result<Self::Scalar>
|
||||
fn hash_to_scalar<CS: CipherSuite>(
|
||||
input: &[&[u8]],
|
||||
mode: Mode,
|
||||
) -> Result<Self::Scalar, InternalError>
|
||||
where
|
||||
<CS::Hash as OutputSizeUser>::OutputSize:
|
||||
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
||||
@@ -62,7 +69,7 @@ where
|
||||
GenericArray::from(STR_HASH_TO_SCALAR).concat(voprf::get_context_string::<CS>(mode));
|
||||
|
||||
<Self as GroupDigest>::hash_to_scalar::<ExpandMsgXmd<CS::Hash>>(input, &dst)
|
||||
.map_err(|_| Error::PointError)
|
||||
.map_err(|_| InternalError::Input)
|
||||
}
|
||||
|
||||
fn base_elem() -> Self::Elem {
|
||||
@@ -85,7 +92,7 @@ where
|
||||
fn deserialize_elem(element_bits: &GenericArray<u8, Self::ElemLen>) -> Result<Self::Elem> {
|
||||
PublicKey::<Self>::from_sec1_bytes(element_bits)
|
||||
.map(|public_key| public_key.to_projective())
|
||||
.map_err(|_| Error::PointError)
|
||||
.map_err(|_| Error::Deserialization)
|
||||
}
|
||||
|
||||
fn random_scalar<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Scalar {
|
||||
@@ -108,6 +115,6 @@ where
|
||||
fn deserialize_scalar(scalar_bits: &GenericArray<u8, Self::ScalarLen>) -> Result<Self::Scalar> {
|
||||
SecretKey::<Self>::from_be_bytes(scalar_bits)
|
||||
.map(|secret_key| *secret_key.to_nonzero_scalar())
|
||||
.map_err(|_| Error::ScalarError)
|
||||
.map_err(|_| Error::Deserialization)
|
||||
}
|
||||
}
|
||||
|
||||
+26
-4
@@ -24,7 +24,7 @@ use subtle::ConstantTimeEq;
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use crate::voprf::Mode;
|
||||
use crate::{CipherSuite, Result};
|
||||
use crate::{CipherSuite, InternalError, Result};
|
||||
|
||||
pub(crate) const STR_HASH_TO_SCALAR: [u8; 13] = *b"HashToScalar-";
|
||||
pub(crate) const STR_HASH_TO_GROUP: [u8; 12] = *b"HashToGroup-";
|
||||
@@ -52,14 +52,28 @@ pub trait Group {
|
||||
/// The byte length necessary to represent scalars
|
||||
type ScalarLen: ArrayLength<u8> + 'static;
|
||||
|
||||
/// transforms a password and domain separation tag (DST) into a curve point
|
||||
fn hash_to_curve<CS: CipherSuite>(msg: &[&[u8]], mode: Mode) -> Result<Self::Elem>
|
||||
/// Transforms a password and domain separation tag (DST) into a curve point
|
||||
///
|
||||
/// # Errors
|
||||
/// [`Error::Input`](crate::Error::Input) if the `input` is empty or longer
|
||||
/// then [`u16::MAX`].
|
||||
fn hash_to_curve<CS: CipherSuite>(
|
||||
input: &[&[u8]],
|
||||
mode: Mode,
|
||||
) -> Result<Self::Elem, InternalError>
|
||||
where
|
||||
<CS::Hash as OutputSizeUser>::OutputSize:
|
||||
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>;
|
||||
|
||||
/// Hashes a slice of pseudo-random bytes to a scalar
|
||||
fn hash_to_scalar<CS: CipherSuite>(input: &[&[u8]], mode: Mode) -> Result<Self::Scalar>
|
||||
///
|
||||
/// # Errors
|
||||
/// [`Error::Input`](crate::Error::Input) if the `input` is empty or longer
|
||||
/// then [`u16::MAX`].
|
||||
fn hash_to_scalar<CS: CipherSuite>(
|
||||
input: &[&[u8]],
|
||||
mode: Mode,
|
||||
) -> Result<Self::Scalar, InternalError>
|
||||
where
|
||||
<CS::Hash as OutputSizeUser>::OutputSize:
|
||||
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>;
|
||||
@@ -75,6 +89,10 @@ pub trait Group {
|
||||
|
||||
/// Return an element from its fixed-length bytes representation. If the
|
||||
/// element is the identity element, return an error.
|
||||
///
|
||||
/// # Errors
|
||||
/// [`Error::Deserialization`](crate::Error::Deserialization) if the element
|
||||
/// is not a valid point on the group or the identity element.
|
||||
fn deserialize_elem(element_bits: &GenericArray<u8, Self::ElemLen>) -> Result<Self::Elem>;
|
||||
|
||||
/// picks a scalar at random
|
||||
@@ -92,6 +110,10 @@ pub trait Group {
|
||||
|
||||
/// Return a scalar from its fixed-length bytes representation. If the
|
||||
/// scalar is zero or invalid, then return an error.
|
||||
///
|
||||
/// # Errors
|
||||
/// [`Error::Deserialization`](crate::Error::Deserialization) if the scalar
|
||||
/// is not a valid point on the group or zero.
|
||||
fn deserialize_scalar(scalar_bits: &GenericArray<u8, Self::ScalarLen>) -> Result<Self::Scalar>;
|
||||
}
|
||||
|
||||
|
||||
+14
-8
@@ -19,7 +19,7 @@ use rand_core::{CryptoRng, RngCore};
|
||||
|
||||
use super::{Group, STR_HASH_TO_GROUP, STR_HASH_TO_SCALAR};
|
||||
use crate::voprf::{self, Mode};
|
||||
use crate::{CipherSuite, Error, Result};
|
||||
use crate::{CipherSuite, Error, InternalError, Result};
|
||||
|
||||
/// [`Group`] implementation for Ristretto255.
|
||||
pub struct Ristretto255;
|
||||
@@ -46,7 +46,10 @@ impl Group for Ristretto255 {
|
||||
|
||||
// Implements the `hash_to_ristretto255()` function from
|
||||
// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-10.txt
|
||||
fn hash_to_curve<CS: CipherSuite>(msg: &[&[u8]], mode: Mode) -> Result<Self::Elem>
|
||||
fn hash_to_curve<CS: CipherSuite>(
|
||||
input: &[&[u8]],
|
||||
mode: Mode,
|
||||
) -> Result<Self::Elem, InternalError>
|
||||
where
|
||||
<CS::Hash as OutputSizeUser>::OutputSize:
|
||||
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
||||
@@ -55,8 +58,8 @@ impl Group for Ristretto255 {
|
||||
GenericArray::from(STR_HASH_TO_GROUP).concat(voprf::get_context_string::<Self>(mode));
|
||||
|
||||
let mut uniform_bytes = GenericArray::<_, U64>::default();
|
||||
ExpandMsgXmd::<CS::Hash>::expand_message(msg, &dst, 64)
|
||||
.map_err(|_| Error::PointError)?
|
||||
ExpandMsgXmd::<CS::Hash>::expand_message(input, &dst, 64)
|
||||
.map_err(|_| InternalError::Input)?
|
||||
.fill_bytes(&mut uniform_bytes);
|
||||
|
||||
Ok(RistrettoPoint::from_uniform_bytes(&uniform_bytes.into()))
|
||||
@@ -64,7 +67,10 @@ impl Group for Ristretto255 {
|
||||
|
||||
// Implements the `HashToScalar()` function from
|
||||
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-07.html#section-4.1
|
||||
fn hash_to_scalar<'a, CS: CipherSuite>(input: &[&[u8]], mode: Mode) -> Result<Self::Scalar>
|
||||
fn hash_to_scalar<'a, CS: CipherSuite>(
|
||||
input: &[&[u8]],
|
||||
mode: Mode,
|
||||
) -> Result<Self::Scalar, InternalError>
|
||||
where
|
||||
<CS::Hash as OutputSizeUser>::OutputSize:
|
||||
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
|
||||
@@ -74,7 +80,7 @@ impl Group for Ristretto255 {
|
||||
|
||||
let mut uniform_bytes = GenericArray::<_, U64>::default();
|
||||
ExpandMsgXmd::<CS::Hash>::expand_message(input, &dst, 64)
|
||||
.map_err(|_| Error::PointError)?
|
||||
.map_err(|_| InternalError::Input)?
|
||||
.fill_bytes(&mut uniform_bytes);
|
||||
|
||||
Ok(Scalar::from_bytes_mod_order_wide(&uniform_bytes.into()))
|
||||
@@ -97,7 +103,7 @@ impl Group for Ristretto255 {
|
||||
CompressedRistretto::from_slice(element_bits)
|
||||
.decompress()
|
||||
.filter(|point| point != &RistrettoPoint::identity())
|
||||
.ok_or(Error::PointError)
|
||||
.ok_or(Error::Deserialization)
|
||||
}
|
||||
|
||||
fn random_scalar<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Scalar {
|
||||
@@ -130,6 +136,6 @@ impl Group for Ristretto255 {
|
||||
fn deserialize_scalar(scalar_bits: &GenericArray<u8, Self::ScalarLen>) -> Result<Self::Scalar> {
|
||||
Scalar::from_canonical_bytes((*scalar_bits).into())
|
||||
.filter(|scalar| scalar != &Scalar::zero())
|
||||
.ok_or(Error::ScalarError)
|
||||
.ok_or(Error::Deserialization)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -34,7 +34,7 @@ fn test_group_properties() -> Result<()> {
|
||||
fn test_identity_element_error<G: Group>() -> Result<()> {
|
||||
let identity = G::identity_elem();
|
||||
let result = G::deserialize_elem(&G::serialize_elem(identity));
|
||||
assert!(matches!(result, Err(Error::PointError)));
|
||||
assert!(matches!(result, Err(Error::Deserialization)));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -43,7 +43,7 @@ fn test_identity_element_error<G: Group>() -> Result<()> {
|
||||
fn test_zero_scalar_error<G: Group>() -> Result<()> {
|
||||
let zero_scalar = G::zero_scalar();
|
||||
let result = G::deserialize_scalar(&G::serialize_scalar(zero_scalar));
|
||||
assert!(matches!(result, Err(Error::ScalarError)));
|
||||
assert!(matches!(result, Err(Error::Deserialization)));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user