Skip to content

Commit

Permalink
Fix hash_to_scalar using OprfGroup instead of KeGroup
Browse files Browse the repository at this point in the history
  • Loading branch information
daxpedda committed Feb 24, 2022
1 parent 09ff213 commit c4a7f92
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 79 deletions.
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ version = "2.0.0-pre.1"

[features]
default = ["ristretto255_u64", "ristretto255_voprf", "serde"]
ristretto255 = ["voprf/ristretto255"]
ristretto255 = ["curve25519-dalek", "voprf/ristretto255"]
ristretto255_fiat_u32 = ["curve25519-dalek/fiat_u32_backend", "ristretto255"]
ristretto255_fiat_u64 = ["curve25519-dalek/fiat_u64_backend", "ristretto255"]
ristretto255_simd = ["curve25519-dalek/simd_backend", "ristretto255"]
Expand All @@ -23,7 +23,7 @@ ristretto255_voprf = ["ristretto255", "voprf/ristretto255-ciphersuite"]
serde = ["serde_", "generic-array/serde", "voprf/serde"]
slow-hash = ["argon2"]
std = ["getrandom", "rand/std", "rand/std_rng", "voprf/std"]
x25519 = []
x25519 = ["curve25519-dalek"]
x25519_fiat_u32 = ["x25519", "x25519-dalek/fiat_u32_backend"]
x25519_fiat_u64 = ["x25519", "x25519-dalek/fiat_u64_backend"]
# x25519-dalek isn't properly re-exposing `simd_backend`.
Expand All @@ -44,7 +44,7 @@ curve25519-dalek = { version = "=4.0.0-pre.1", default-features = false, optiona
derive-where = { version = "=1.0.0-rc.3", features = ["zeroize-on-drop"] }
digest = "0.10"
displaydoc = { version = "0.2", default-features = false }
elliptic-curve = { version = "0.12.0-pre.1", features = ["sec1"] }
elliptic-curve = { version = "0.12.0-pre.1", features = ["hash2curve", "sec1"] }
generic-array = "0.14"
getrandom = { version = "0.2", optional = true }
hkdf = "0.12"
Expand Down
7 changes: 3 additions & 4 deletions src/envelope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@ use generic_array::{ArrayLength, GenericArray};
use hkdf::Hkdf;
use hmac::{Hmac, Mac};
use rand::{CryptoRng, RngCore};
use voprf::Group;
use zeroize::{Zeroize, ZeroizeOnDrop};

use crate::ciphersuite::{CipherSuite, OprfGroup, OprfHash};
use crate::ciphersuite::{CipherSuite, OprfHash};
use crate::errors::utils::check_slice_size;
use crate::errors::{InternalError, ProtocolError};
use crate::hash::{Hash, OutputSize, ProxyHash};
Expand Down Expand Up @@ -364,7 +363,7 @@ where
.map_err(|_| InternalError::HkdfError)?;
let client_static_keypair = KeyPair::<CS::KeGroup>::from_private_key_slice(
// TODO: Use `KeGroup` instead of `OprfGroup` here.
&OprfGroup::<CS>::serialize_scalar(OprfGroup::<CS>::hash_to_scalar::<CS::OprfGroup>(
&CS::KeGroup::serialize_sk(&CS::KeGroup::hash_to_scalar::<OprfHash<CS>>(
&[keypair_seed.as_slice()],
&GenericArray::from(STR_OPAQUE_DERIVE_AUTH_KEY_PAIR),
)?),
Expand All @@ -390,7 +389,7 @@ where
.expand(&nonce.concat(STR_PRIVATE_KEY.into()), &mut keypair_seed)
.map_err(|_| InternalError::HkdfError)?;
let client_static_keypair = KeyPair::<CS::KeGroup>::from_private_key_slice(
&OprfGroup::<CS>::serialize_scalar(OprfGroup::<CS>::hash_to_scalar::<CS::OprfGroup>(
&CS::KeGroup::serialize_sk(&CS::KeGroup::hash_to_scalar::<OprfHash<CS>>(
&[keypair_seed.as_slice()],
&GenericArray::from(STR_OPAQUE_DERIVE_AUTH_KEY_PAIR),
)?),
Expand Down
16 changes: 4 additions & 12 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ pub enum InternalError<T = Infallible> {
},
/// Could not decompress point.
PointError,
/// Computing the hash-to-curve function failed
HashToCurveError,
/// Size of input is empty or longer then [`u16::MAX`].
HashToScalar,
/// Computing HKDF failed while deriving subkeys
HkdfError,
/// Computing HMAC failed while supplying a secret key
Expand All @@ -45,14 +45,10 @@ pub enum InternalError<T = Infallible> {
/** This error occurs when attempting to open an envelope of the wrong
type (base mode, custom identifier) */
IncompatibleEnvelopeModeError,
/// This error occurs when the inner envelope is malformed
InvalidInnerEnvelopeError,
/// Error from the OPRF evaluation
OprfError(voprf::Error),
/// Error from the OPRF evaluation
OprfInternalError(voprf::InternalError),
/// Error encountered when attempting to produce a keypair
InvalidKeypairError,
}

impl<T: Debug> Debug for InternalError<T> {
Expand All @@ -71,20 +67,18 @@ impl<T: Debug> Debug for InternalError<T> {
.field("actual_len", actual_len)
.finish(),
Self::PointError => f.debug_tuple("PointError").finish(),
Self::HashToCurveError => f.debug_tuple("HashToCurveError").finish(),
Self::HashToScalar => f.debug_tuple("HashToScalar").finish(),
Self::HkdfError => f.debug_tuple("HkdfError").finish(),
Self::HmacError => f.debug_tuple("HmacError").finish(),
Self::SlowHashError => f.debug_tuple("SlowHashError").finish(),
Self::SealOpenHmacError => f.debug_tuple("SealOpenHmacError").finish(),
Self::IncompatibleEnvelopeModeError => {
f.debug_tuple("IncompatibleEnvelopeModeError").finish()
}
Self::InvalidInnerEnvelopeError => f.debug_tuple("InvalidInnerEnvelopeError").finish(),
Self::OprfError(error) => f.debug_tuple("OprfError").field(error).finish(),
Self::OprfInternalError(error) => {
f.debug_tuple("OprfInternalError").field(error).finish()
}
Self::InvalidKeypairError => f.debug_tuple("InvalidKeypairError").finish(),
}
}
}
Expand All @@ -108,16 +102,14 @@ impl InternalError {
actual_len,
},
Self::PointError => InternalError::PointError,
Self::HashToCurveError => InternalError::HashToCurveError,
Self::HashToScalar => InternalError::HashToScalar,
Self::HkdfError => InternalError::HkdfError,
Self::HmacError => InternalError::HmacError,
Self::SlowHashError => InternalError::SlowHashError,
Self::SealOpenHmacError => InternalError::SealOpenHmacError,
Self::IncompatibleEnvelopeModeError => InternalError::IncompatibleEnvelopeModeError,
Self::InvalidInnerEnvelopeError => InternalError::InvalidInnerEnvelopeError,
Self::OprfError(error) => InternalError::OprfError(error),
Self::OprfInternalError(error) => InternalError::OprfInternalError(error),
Self::InvalidKeypairError => InternalError::InvalidKeypairError,
}
}
}
Expand Down
28 changes: 25 additions & 3 deletions src/key_exchange/group/elliptic_curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,29 @@
// License, Version 2.0 found in the LICENSE-APACHE file in the root directory
// of this source tree.

use digest::core_api::BlockSizeUser;
use digest::Digest;
use elliptic_curve::group::cofactor::CofactorGroup;
use elliptic_curve::hash2curve::{ExpandMsgXmd, FromOkm, GroupDigest};
use elliptic_curve::sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint};
use elliptic_curve::{
AffinePoint, Curve, FieldSize, ProjectiveArithmetic, ProjectivePoint, PublicKey, SecretKey,
AffinePoint, Curve, FieldSize, NonZeroScalar, ProjectiveArithmetic, ProjectivePoint, PublicKey,
Scalar, SecretKey,
};
use generic_array::typenum::{IsLess, IsLessOrEqual, U256};
use generic_array::GenericArray;
use rand::{CryptoRng, RngCore};

use super::KeGroup;
use crate::errors::InternalError;

impl<G: Curve + ProjectiveArithmetic> KeGroup for G
impl<G: Curve + GroupDigest + ProjectiveArithmetic> KeGroup for G
where
FieldSize<Self>: ModulusSize,
AffinePoint<Self>: FromEncodedPoint<Self> + ToEncodedPoint<Self>,
ProjectivePoint<Self>: ToEncodedPoint<Self>,
ProjectivePoint<Self>: CofactorGroup + ToEncodedPoint<Self>,
Scalar<Self>: FromOkm,
//AffinePoint<Self>: FromEncodedPoint<Self> + ToEncodedPoint<Self>,
{
type Pk = PublicKey<Self>;

Expand All @@ -41,6 +49,20 @@ where
SecretKey::<Self>::random(rng)
}

// Implements the `HashToScalar()` function
fn hash_to_scalar<H>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Sk, InternalError>
where
H: Digest + BlockSizeUser,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>,
{
Option::<NonZeroScalar<Self>>::from(NonZeroScalar::new(
<Self as GroupDigest>::hash_to_scalar::<ExpandMsgXmd<H>>(input, dst)
.map_err(|_| InternalError::HashToScalar)?,
))
.map(SecretKey::from)
.ok_or(InternalError::HashToScalar)
}

fn public_key(sk: &Self::Sk) -> Self::Pk {
sk.public_key()
}
Expand Down
13 changes: 13 additions & 0 deletions src/key_exchange/group/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ pub mod ristretto255;
#[cfg(feature = "x25519")]
pub mod x25519;

use digest::core_api::BlockSizeUser;
use digest::Digest;
use generic_array::typenum::{IsLess, IsLessOrEqual, U256};
use generic_array::{ArrayLength, GenericArray};
use rand::{CryptoRng, RngCore};

Expand All @@ -38,6 +41,16 @@ pub trait KeGroup {
/// Generate a random secret key
fn random_sk<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Sk;

/// Hashes a slice of pseudo-random bytes to a scalar
///
/// # Errors
/// [`Error::Input`](crate::Error::Input) if the `input` is empty or longer
/// then [`u16::MAX`].
fn hash_to_scalar<H>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Sk, InternalError>
where
H: Digest + BlockSizeUser,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>;

/// Return a public key from its secret key
fn public_key(sk: &Self::Sk) -> Self::Pk;

Expand Down
20 changes: 18 additions & 2 deletions src/key_exchange/group/ristretto255.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT;
use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint};
use curve25519_dalek::scalar::Scalar;
use digest::core_api::BlockSizeUser;
use digest::OutputSizeUser;
use generic_array::typenum::{IsLess, IsLessOrEqual, U256, U32};
use digest::{Digest, OutputSizeUser};
use elliptic_curve::hash2curve::{ExpandMsg, ExpandMsgXmd, Expander};
use generic_array::typenum::{IsLess, IsLessOrEqual, U256, U32, U64};
use generic_array::GenericArray;
use rand::{CryptoRng, RngCore};
use voprf::Group;
Expand Down Expand Up @@ -68,6 +69,21 @@ impl KeGroup for Ristretto255 {
}
}

// Implements the `HashToScalar()` function from
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-08.html#section-4.1
fn hash_to_scalar<'a, H>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Sk, InternalError>
where
H: Digest + BlockSizeUser,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>,
{
let mut uniform_bytes = GenericArray::<_, U64>::default();
ExpandMsgXmd::<H>::expand_message(input, dst, 64)
.map_err(|_| InternalError::HashToScalar)?
.fill_bytes(&mut uniform_bytes);

Ok(Scalar::from_bytes_mod_order_wide(&uniform_bytes.into()))
}

fn public_key(sk: &Self::Sk) -> Self::Pk {
RISTRETTO_BASEPOINT_POINT * sk
}
Expand Down
23 changes: 22 additions & 1 deletion src/key_exchange/group/x25519.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@

//! Key Exchange group implementation for X25519

use generic_array::typenum::U32;
use curve25519_dalek::scalar::Scalar;
use digest::core_api::BlockSizeUser;
use digest::Digest;
use elliptic_curve::hash2curve::{ExpandMsg, ExpandMsgXmd, Expander};
use generic_array::typenum::{IsLess, IsLessOrEqual, U256, U32, U64};
use generic_array::GenericArray;
use rand::{CryptoRng, RngCore};
use x25519_dalek::{PublicKey, StaticSecret};
Expand Down Expand Up @@ -50,6 +54,23 @@ impl KeGroup for X25519 {
}
}

// Implements the `HashToScalar()` function from
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-08.html#section-4.1
fn hash_to_scalar<'a, H>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Sk, InternalError>
where
H: Digest + BlockSizeUser,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>,
{
let mut uniform_bytes = GenericArray::<_, U64>::default();
ExpandMsgXmd::<H>::expand_message(input, dst, 64)
.map_err(|_| InternalError::HashToScalar)?
.fill_bytes(&mut uniform_bytes);

Ok(StaticSecret::from(
Scalar::from_bytes_mod_order_wide(&uniform_bytes.into()).to_bytes(),
))
}

fn public_key(sk: &Self::Sk) -> Self::Pk {
PublicKey::from(sk)
}
Expand Down

0 comments on commit c4a7f92

Please sign in to comment.