-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Rely on elliptic-curve for hash-to-curve and P-256 implementations * Update MSRV * Remove unnecessary `#[macro_use]` * Re-introduce `CipherSuite` * Provide types for length shortcuts * Remove `SUITE_ID` from `Group` * Blanket implementation for RustCrypto `Curve`s * Remove the p256 crate feature * Rename `ristretto_*` crate features to `ristretto-*` for consistency * Remove unnecessary allowed Clippy lints * Remove some unnecessary constraints
- Loading branch information
Showing
15 changed files
with
1,028 additions
and
1,633 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,65 +2,60 @@ | |
authors = ["Kevin Lewi <[email protected]>"] | ||
categories = ["no-std", "algorithms", "cryptography"] | ||
description = "An implementation of a verifiable oblivious pseudorandom function (VOPRF)" | ||
edition = "2018" | ||
edition = "2021" | ||
keywords = ["oprf"] | ||
license = "MIT" | ||
name = "voprf" | ||
readme = "README.md" | ||
repository = "https://github.com/novifinancial/voprf/" | ||
resolver = "2" | ||
rust-version = "1.51" | ||
rust-version = "1.57" | ||
version = "0.3.0" | ||
|
||
[features] | ||
alloc = [] | ||
danger = [] | ||
default = ["ristretto255_u64", "serde"] | ||
p256 = [ | ||
"alloc", | ||
"num-bigint", | ||
"num-integer", | ||
"num-traits", | ||
"once_cell", | ||
"p256_", | ||
] | ||
default = ["ristretto255-ciphersuite", "ristretto255-u64", "serde"] | ||
ristretto255 = ["generic-array/more_lengths"] | ||
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"] | ||
ristretto255_u32 = ["curve25519-dalek/u32_backend", "ristretto255"] | ||
ristretto255_u64 = ["curve25519-dalek/u64_backend", "ristretto255"] | ||
ristretto255-ciphersuite = ["ristretto255", "sha2"] | ||
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"] | ||
ristretto255-u32 = ["curve25519-dalek/u32_backend", "ristretto255"] | ||
ristretto255-u64 = ["curve25519-dalek/u64_backend", "ristretto255"] | ||
std = ["alloc"] | ||
|
||
[dependencies] | ||
curve25519-dalek = { version = "3", default-features = false, optional = true } | ||
derive-where = { version = "1.0.0-rc.1", features = ["zeroize"] } | ||
digest = "0.10" | ||
displaydoc = { version = "0.2", default-features = false } | ||
elliptic-curve = { version = "0.12.0-pre.1", features = [ | ||
"hash2curve", | ||
"sec1", | ||
"voprf", | ||
] } | ||
generic-array = "0.14" | ||
num-bigint = { version = "0.4", default-features = false, optional = true } | ||
num-integer = { version = "0.1", default-features = false, optional = true } | ||
num-traits = { version = "0.2", default-features = false, optional = true } | ||
once_cell = { version = "1", default-features = false, optional = true } | ||
p256_ = { package = "p256", version = "0.10", default-features = false, features = [ | ||
"arithmetic", | ||
], optional = true } | ||
rand_core = { version = "0.6", default-features = false } | ||
serde = { version = "1", default-features = false, features = [ | ||
"derive", | ||
], optional = true } | ||
sha2 = { version = "0.10", default-features = false, optional = true } | ||
subtle = { version = "2.3", default-features = false } | ||
zeroize = { version = "1", default-features = false } | ||
|
||
[dev-dependencies] | ||
generic-array = { version = "0.14", features = ["more_lengths"] } | ||
hex = "0.4" | ||
json = "0.12" | ||
p256 = { version = "0.11.0-pre.0", default-features = false, features = [ | ||
"hash2curve", | ||
"voprf", | ||
] } | ||
proptest = "1" | ||
rand = "0.8" | ||
regex = "1" | ||
sha2 = "0.10" | ||
|
||
[package.metadata.docs.rs] | ||
features = ["danger", "p256", "std"] | ||
features = ["danger", "std"] | ||
targets = [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// Copyright (c) Facebook, Inc. and its affiliates. | ||
// | ||
// This source code is licensed under both the MIT license found in the | ||
// LICENSE-MIT file in the root directory of this source tree and the Apache | ||
// License, Version 2.0 found in the LICENSE-APACHE file in the root directory | ||
// of this source tree. | ||
|
||
//! Defines the CipherSuite trait to specify the underlying primitives for VOPRF | ||
use digest::core_api::BlockSizeUser; | ||
use digest::{Digest, OutputSizeUser}; | ||
use elliptic_curve::VoprfParameters; | ||
use generic_array::typenum::{IsLess, IsLessOrEqual, U256}; | ||
|
||
use crate::Group; | ||
|
||
/// Configures the underlying primitives used in VOPRF | ||
pub trait CipherSuite | ||
where | ||
<Self::Hash as OutputSizeUser>::OutputSize: | ||
IsLess<U256> + IsLessOrEqual<<Self::Hash as BlockSizeUser>::BlockSize>, | ||
{ | ||
/// The ciphersuite identifier as dictated by | ||
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-08.html> | ||
const ID: u16; | ||
|
||
/// A finite cyclic group along with a point representation that allows some | ||
/// customization on how to hash an input to a curve point. See [`Group`]. | ||
type Group: Group; | ||
|
||
/// The main hash function to use (for HKDF computations and hashing | ||
/// transcripts). | ||
type Hash: BlockSizeUser + Digest; | ||
} | ||
|
||
impl<T: VoprfParameters> CipherSuite for T | ||
where | ||
T: Group, | ||
T::Hash: BlockSizeUser + Digest, | ||
<T::Hash as OutputSizeUser>::OutputSize: | ||
IsLess<U256> + IsLessOrEqual<<T::Hash as BlockSizeUser>::BlockSize>, | ||
{ | ||
const ID: u16 = T::ID; | ||
|
||
type Group = T; | ||
|
||
type Hash = T::Hash; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
// Copyright (c) Facebook, Inc. and its affiliates. | ||
// | ||
// This source code is licensed under both the MIT license found in the | ||
// LICENSE-MIT file in the root directory of this source tree and the Apache | ||
// 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::OutputSizeUser; | ||
use elliptic_curve::group::cofactor::CofactorGroup; | ||
use elliptic_curve::hash2curve::{ExpandMsgXmd, FromOkm, GroupDigest}; | ||
use elliptic_curve::sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint}; | ||
use elliptic_curve::{ | ||
AffinePoint, Field, FieldSize, Group as _, ProjectivePoint, PublicKey, Scalar, SecretKey, | ||
}; | ||
use generic_array::sequence::Concat; | ||
use generic_array::typenum::{IsLess, IsLessOrEqual, U256}; | ||
use generic_array::GenericArray; | ||
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}; | ||
|
||
impl<C> Group for C | ||
where | ||
C: GroupDigest, | ||
ProjectivePoint<Self>: CofactorGroup, | ||
FieldSize<Self>: ModulusSize, | ||
AffinePoint<Self>: FromEncodedPoint<Self> + ToEncodedPoint<Self>, | ||
Scalar<Self>: FromOkm, | ||
{ | ||
type Elem = ProjectivePoint<Self>; | ||
|
||
type ElemLen = <FieldSize<Self> as ModulusSize>::CompressedPointSize; | ||
|
||
type Scalar = Scalar<Self>; | ||
|
||
type ScalarLen = FieldSize<Self>; | ||
|
||
// 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> | ||
where | ||
<CS::Hash as OutputSizeUser>::OutputSize: | ||
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>, | ||
{ | ||
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) | ||
} | ||
|
||
// Implements the `HashToScalar()` function | ||
fn hash_to_scalar<CS: CipherSuite>(input: &[&[u8]], mode: Mode) -> Result<Self::Scalar> | ||
where | ||
<CS::Hash as OutputSizeUser>::OutputSize: | ||
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>, | ||
{ | ||
let dst = | ||
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) | ||
} | ||
|
||
fn base_elem() -> Self::Elem { | ||
ProjectivePoint::<Self>::generator() | ||
} | ||
|
||
fn identity_elem() -> Self::Elem { | ||
ProjectivePoint::<Self>::identity() | ||
} | ||
|
||
fn serialize_elem(elem: Self::Elem) -> GenericArray<u8, Self::ElemLen> { | ||
let point: AffinePoint<Self> = elem.into(); | ||
let bytes = point.to_encoded_point(true); | ||
let bytes = bytes.as_bytes(); | ||
let mut result = GenericArray::default(); | ||
result[..bytes.len()].copy_from_slice(bytes); | ||
result | ||
} | ||
|
||
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) | ||
} | ||
|
||
fn random_scalar<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Scalar { | ||
*SecretKey::<Self>::random(rng).to_nonzero_scalar() | ||
} | ||
|
||
fn invert_scalar(scalar: Self::Scalar) -> Self::Scalar { | ||
Option::from(scalar.invert()).unwrap() | ||
} | ||
|
||
#[cfg(test)] | ||
fn zero_scalar() -> Self::Scalar { | ||
Scalar::<Self>::zero() | ||
} | ||
|
||
fn serialize_scalar(scalar: Self::Scalar) -> GenericArray<u8, Self::ScalarLen> { | ||
scalar.into() | ||
} | ||
|
||
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) | ||
} | ||
} |
Oops, something went wrong.