Skip to content

Commit 5910c2a

Browse files
committed
Update to draft 19
1 parent 40d8129 commit 5910c2a

15 files changed

Lines changed: 616 additions & 578 deletions

File tree

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ jobs:
4343
- --features serde
4444
toolchain:
4545
- stable
46-
- 1.60.0
46+
- 1.61.0
4747
name: test
4848
steps:
4949
- name: Checkout sources

Cargo.toml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ license = "MIT"
88
name = "voprf"
99
readme = "README.md"
1010
repository = "https://github.com/novifinancial/voprf/"
11-
rust-version = "1.60"
11+
rust-version = "1.61"
1212
version = "0.5.0-pre.2"
1313

1414
[features]
@@ -28,7 +28,7 @@ curve25519-dalek = { version = "=4.0.0-rc.1", default-features = false, features
2828
derive-where = { version = "1", features = ["zeroize-on-drop"] }
2929
digest = "0.10"
3030
displaydoc = { version = "0.2", default-features = false }
31-
elliptic-curve = { version = "0.12", features = [
31+
elliptic-curve = { version = "=0.13.0-pre.5", features = [
3232
"hash2curve",
3333
"sec1",
3434
"voprf",
@@ -45,7 +45,7 @@ zeroize = { version = "1.5", default-features = false }
4545
[dev-dependencies]
4646
generic-array = { version = "0.14", features = ["more_lengths"] }
4747
hex = "0.4"
48-
p256 = { version = "0.12", default-features = false, features = [
48+
p256 = { version = "=0.13.0-pre", default-features = false, features = [
4949
"hash2curve",
5050
"voprf",
5151
] }
@@ -59,3 +59,6 @@ sha2 = "0.10"
5959
all-features = true
6060
rustdoc-args = ["--cfg", "docsrs"]
6161
targets = []
62+
63+
[patch.crates-io]
64+
p256 = { git = "https://github.com/RustCrypto/elliptic-curves", rev = "136fed7944d53c0508b1a93cd97bdab46891bcf7" }

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ voprf = "0.5.0-pre.2"
2121

2222
### Minimum Supported Rust Version
2323

24-
Rust **1.60** or higher.
24+
Rust **1.61** or higher.
2525

2626
Contributors
2727
------------

src/ciphersuite.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
//! Defines the CipherSuite trait to specify the underlying primitives for VOPRF
99
1010
use digest::core_api::BlockSizeUser;
11-
use digest::{Digest, OutputSizeUser};
11+
use digest::{FixedOutput, HashMarker, OutputSizeUser};
1212
use elliptic_curve::VoprfParameters;
1313
use generic_array::typenum::{IsLess, IsLessOrEqual, U256};
1414

@@ -22,25 +22,25 @@ where
2222
{
2323
/// The ciphersuite identifier as dictated by
2424
/// <https://datatracker.ietf.org/doc/draft-irtf-cfrg-voprf/>
25-
const ID: u16;
25+
const ID: &'static str;
2626

2727
/// A finite cyclic group along with a point representation that allows some
2828
/// customization on how to hash an input to a curve point. See [`Group`].
2929
type Group: Group;
3030

3131
/// The main hash function to use (for HKDF computations and hashing
3232
/// transcripts).
33-
type Hash: BlockSizeUser + Digest;
33+
type Hash: BlockSizeUser + Default + FixedOutput + HashMarker;
3434
}
3535

3636
impl<T: VoprfParameters> CipherSuite for T
3737
where
3838
T: Group,
39-
T::Hash: BlockSizeUser + Digest,
39+
T::Hash: BlockSizeUser + Default + FixedOutput + HashMarker,
4040
<T::Hash as OutputSizeUser>::OutputSize:
4141
IsLess<U256> + IsLessOrEqual<<T::Hash as BlockSizeUser>::BlockSize>,
4242
{
43-
const ID: u16 = T::ID;
43+
const ID: &'static str = T::ID;
4444

4545
type Group = T;
4646

src/common.rs

Lines changed: 72 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@
88
//! Common functionality between multiple OPRF modes.
99
1010
use core::convert::TryFrom;
11+
use core::ops::Add;
1112

1213
use derive_where::derive_where;
1314
use digest::core_api::BlockSizeUser;
1415
use digest::{Digest, Output, OutputSizeUser};
1516
use generic_array::sequence::Concat;
16-
use generic_array::typenum::{IsLess, IsLessOrEqual, Unsigned, U11, U2, U256};
17+
use generic_array::typenum::{IsLess, IsLessOrEqual, Unsigned, U2, U256, U9};
1718
use generic_array::{ArrayLength, GenericArray};
1819
use rand_core::{CryptoRng, RngCore};
1920
use subtle::ConstantTimeEq;
@@ -33,7 +34,7 @@ pub(crate) const STR_DERIVE_KEYPAIR: [u8; 13] = *b"DeriveKeyPair";
3334
pub(crate) const STR_COMPOSITE: [u8; 9] = *b"Composite";
3435
pub(crate) const STR_CHALLENGE: [u8; 9] = *b"Challenge";
3536
pub(crate) const STR_INFO: [u8; 4] = *b"Info";
36-
pub(crate) const STR_VOPRF: [u8; 8] = *b"VOPRF10-";
37+
pub(crate) const STR_OPRF: [u8; 7] = *b"OPRFV1-";
3738
pub(crate) const STR_HASH_TO_SCALAR: [u8; 13] = *b"HashToScalar-";
3839
pub(crate) const STR_HASH_TO_GROUP: [u8; 12] = *b"HashToGroup-";
3940

@@ -194,9 +195,9 @@ where
194195
&STR_CHALLENGE,
195196
];
196197

197-
let dst = GenericArray::from(STR_HASH_TO_SCALAR).concat(create_context_string::<CS>(mode));
198+
let dst = Dst::new::<CS, _, _>(STR_HASH_TO_SCALAR, mode);
198199
// This can't fail, the size of the `input` is known.
199-
let c_scalar = CS::Group::hash_to_scalar::<CS::Hash>(&h2_input, &dst).unwrap();
200+
let c_scalar = CS::Group::hash_to_scalar::<CS::Hash>(&h2_input, &dst.as_dst()).unwrap();
200201
let s_scalar = r - &(c_scalar * &k);
201202

202203
Ok(Proof { c_scalar, s_scalar })
@@ -254,9 +255,9 @@ where
254255
&STR_CHALLENGE,
255256
];
256257

257-
let dst = GenericArray::from(STR_HASH_TO_SCALAR).concat(create_context_string::<CS>(mode));
258+
let dst = Dst::new::<CS, _, _>(STR_HASH_TO_SCALAR, mode);
258259
// This can't fail, the size of the `input` is known.
259-
let c = CS::Group::hash_to_scalar::<CS::Hash>(&h2_input, &dst).unwrap();
260+
let c = CS::Group::hash_to_scalar::<CS::Hash>(&h2_input, &dst.as_dst()).unwrap();
260261

261262
match c.ct_eq(&proof.c_scalar).into() {
262263
true => Ok(()),
@@ -296,16 +297,16 @@ where
296297
let len = u16::try_from(c_slice.len()).map_err(|_| Error::Batch)?;
297298

298299
// seedDST = "Seed-" || contextString
299-
let seed_dst = GenericArray::from(STR_SEED).concat(create_context_string::<CS>(mode));
300+
let seed_dst = Dst::new::<CS, _, _>(STR_SEED, mode);
300301

301302
// h1Input = I2OSP(len(Bm), 2) || Bm ||
302303
// I2OSP(len(seedDST), 2) || seedDST
303304
// seed = Hash(h1Input)
304305
let seed = CS::Hash::new()
305306
.chain_update(elem_len)
306307
.chain_update(CS::Group::serialize_elem(b))
307-
.chain_update(i2osp_2_array(&seed_dst))
308-
.chain_update(seed_dst)
308+
.chain_update(seed_dst.i2osp_2())
309+
.chain_update_multi(&seed_dst.as_dst())
309310
.finalize();
310311
let seed_len = i2osp_2_array(&seed);
311312

@@ -332,9 +333,9 @@ where
332333
&STR_COMPOSITE,
333334
];
334335

335-
let dst = GenericArray::from(STR_HASH_TO_SCALAR).concat(create_context_string::<CS>(mode));
336+
let dst = Dst::new::<CS, _, _>(STR_HASH_TO_SCALAR, mode);
336337
// This can't fail, the size of the `input` is known.
337-
let di = CS::Group::hash_to_scalar::<CS::Hash>(&h2_input, &dst).unwrap();
338+
let di = CS::Group::hash_to_scalar::<CS::Hash>(&h2_input, &dst.as_dst()).unwrap();
338339
m = c * &di + &m;
339340
z = match k_option {
340341
Some(_) => z,
@@ -365,8 +366,7 @@ where
365366
<CS::Hash as OutputSizeUser>::OutputSize:
366367
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
367368
{
368-
let context_string = create_context_string::<CS>(mode);
369-
let dst = GenericArray::from(STR_DERIVE_KEYPAIR).concat(context_string);
369+
let dst = Dst::new::<CS, _, _>(STR_DERIVE_KEYPAIR, mode);
370370

371371
let info_len = i2osp_2(info.len()).map_err(|_| Error::DeriveKeyPair)?;
372372

@@ -376,7 +376,7 @@ where
376376
// || contextString)
377377
let sk_s = CS::Group::hash_to_scalar::<CS::Hash>(
378378
&[seed, &info_len, info, &counter.to_be_bytes()],
379-
&dst,
379+
&dst.as_dst(),
380380
)
381381
.map_err(|_| Error::DeriveKeyPair)?;
382382

@@ -455,8 +455,8 @@ where
455455
<CS::Hash as OutputSizeUser>::OutputSize:
456456
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
457457
{
458-
let dst = GenericArray::from(STR_HASH_TO_GROUP).concat(create_context_string::<CS>(mode));
459-
CS::Group::hash_to_curve::<CS::Hash>(&[input], &dst).map_err(|_| Error::Input)
458+
let dst = Dst::new::<CS, _, _>(STR_HASH_TO_GROUP, mode);
459+
CS::Group::hash_to_curve::<CS::Hash>(&[input], &dst.as_dst()).map_err(|_| Error::Input)
460460
}
461461

462462
/// Internal function that finalizes the hash input for OPRF, VOPRF & POPRF.
@@ -497,16 +497,64 @@ where
497497
.finalize())
498498
}
499499

500-
/// Generates the contextString parameter as defined in
501-
/// <https://datatracker.ietf.org/doc/draft-irtf-cfrg-voprf/>
502-
pub(crate) fn create_context_string<CS: CipherSuite>(mode: Mode) -> GenericArray<u8, U11>
500+
pub(crate) struct Dst<L: ArrayLength<u8>> {
501+
dst_1: GenericArray<u8, L>,
502+
dst_2: &'static str,
503+
}
504+
505+
impl<L: ArrayLength<u8>> Dst<L> {
506+
pub(crate) fn new<CS: CipherSuite, T, TL: ArrayLength<u8>>(par_1: T, mode: Mode) -> Self
507+
where
508+
T: Into<GenericArray<u8, TL>>,
509+
TL: Add<U9, Output = L>,
510+
<CS::Hash as OutputSizeUser>::OutputSize:
511+
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
512+
{
513+
let par_1 = par_1.into();
514+
// Generates the contextString parameter as defined in
515+
// <https://datatracker.ietf.org/doc/draft-irtf-cfrg-voprf/>
516+
let par_2 = GenericArray::from(STR_OPRF)
517+
.concat([mode.to_u8()].into())
518+
.concat([b'-'].into());
519+
520+
let dst_1 = par_1.concat(par_2);
521+
let dst_2 = CS::ID;
522+
523+
assert!(
524+
L::USIZE + dst_2.len() <= u16::MAX.into(),
525+
"constructed DST longer then {}",
526+
u16::MAX
527+
);
528+
529+
Self { dst_1, dst_2 }
530+
}
531+
532+
pub(crate) fn as_dst(&self) -> [&[u8]; 2] {
533+
[&self.dst_1, self.dst_2.as_bytes()]
534+
}
535+
536+
pub(crate) fn i2osp_2(&self) -> [u8; 2] {
537+
u16::try_from(L::USIZE + self.dst_2.len())
538+
.unwrap()
539+
.to_be_bytes()
540+
}
541+
}
542+
543+
trait DigestExt {
544+
fn chain_update_multi(self, data: &[&[u8]]) -> Self;
545+
}
546+
547+
impl<T> DigestExt for T
503548
where
504-
<CS::Hash as OutputSizeUser>::OutputSize:
505-
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
549+
T: Digest,
506550
{
507-
GenericArray::from(STR_VOPRF)
508-
.concat([mode.to_u8()].into())
509-
.concat(CS::ID.to_be_bytes().into())
551+
fn chain_update_multi(mut self, datas: &[&[u8]]) -> Self {
552+
for data in datas {
553+
self.update(data)
554+
}
555+
556+
self
557+
}
510558
}
511559

512560
///////////////////////

src/group/elliptic_curve.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
// of this source tree.
77

88
use digest::core_api::BlockSizeUser;
9-
use digest::Digest;
9+
use digest::{FixedOutput, HashMarker};
1010
use elliptic_curve::group::cofactor::CofactorGroup;
1111
use elliptic_curve::hash2curve::{ExpandMsgXmd, FromOkm, GroupDigest};
1212
use elliptic_curve::sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint};
1313
use elliptic_curve::{
14-
AffinePoint, Field, FieldSize, Group as _, ProjectivePoint, PublicKey, Scalar, SecretKey,
14+
AffinePoint, Field, FieldBytesSize, Group as _, ProjectivePoint, PublicKey, Scalar, SecretKey,
1515
};
1616
use generic_array::typenum::{IsLess, IsLessOrEqual, U256};
1717
use generic_array::GenericArray;
@@ -24,32 +24,32 @@ impl<C> Group for C
2424
where
2525
C: GroupDigest,
2626
ProjectivePoint<Self>: CofactorGroup + ToEncodedPoint<Self>,
27-
FieldSize<Self>: ModulusSize,
27+
FieldBytesSize<Self>: ModulusSize,
2828
AffinePoint<Self>: FromEncodedPoint<Self> + ToEncodedPoint<Self>,
2929
Scalar<Self>: FromOkm,
3030
{
3131
type Elem = ProjectivePoint<Self>;
3232

33-
type ElemLen = <FieldSize<Self> as ModulusSize>::CompressedPointSize;
33+
type ElemLen = <FieldBytesSize<Self> as ModulusSize>::CompressedPointSize;
3434

3535
type Scalar = Scalar<Self>;
3636

37-
type ScalarLen = FieldSize<Self>;
37+
type ScalarLen = FieldBytesSize<Self>;
3838

3939
// Implements the `hash_to_curve()` function from
4040
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3
41-
fn hash_to_curve<H>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Elem, InternalError>
41+
fn hash_to_curve<H>(input: &[&[u8]], dst: &[&[u8]]) -> Result<Self::Elem, InternalError>
4242
where
43-
H: Digest + BlockSizeUser,
43+
H: BlockSizeUser + Default + FixedOutput + HashMarker,
4444
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>,
4545
{
4646
Self::hash_from_bytes::<ExpandMsgXmd<H>>(input, dst).map_err(|_| InternalError::Input)
4747
}
4848

4949
// Implements the `HashToScalar()` function
50-
fn hash_to_scalar<H>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Scalar, InternalError>
50+
fn hash_to_scalar<H>(input: &[&[u8]], dst: &[&[u8]]) -> Result<Self::Scalar, InternalError>
5151
where
52-
H: Digest + BlockSizeUser,
52+
H: BlockSizeUser + Default + FixedOutput + HashMarker,
5353
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>,
5454
{
5555
<Self as GroupDigest>::hash_to_scalar::<ExpandMsgXmd<H>>(input, dst)
@@ -92,15 +92,15 @@ where
9292

9393
#[cfg(test)]
9494
fn zero_scalar() -> Self::Scalar {
95-
Scalar::<Self>::zero()
95+
Scalar::<Self>::ZERO
9696
}
9797

9898
fn serialize_scalar(scalar: Self::Scalar) -> GenericArray<u8, Self::ScalarLen> {
9999
scalar.into()
100100
}
101101

102102
fn deserialize_scalar(scalar_bits: &[u8]) -> Result<Self::Scalar> {
103-
SecretKey::<Self>::from_be_bytes(scalar_bits)
103+
SecretKey::<Self>::from_slice(scalar_bits)
104104
.map(|secret_key| *secret_key.to_nonzero_scalar())
105105
.map_err(|_| Error::Deserialization)
106106
}

src/group/mod.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ mod ristretto;
1414
use core::ops::{Add, Mul, Sub};
1515

1616
use digest::core_api::BlockSizeUser;
17-
use digest::Digest;
17+
use digest::{FixedOutput, HashMarker};
1818
use generic_array::typenum::{IsLess, IsLessOrEqual, U256};
1919
use generic_array::{ArrayLength, GenericArray};
2020
use rand_core::{CryptoRng, RngCore};
@@ -54,19 +54,19 @@ pub trait Group {
5454
/// # Errors
5555
/// [`Error::Input`](crate::Error::Input) if the `input` is empty or longer
5656
/// then [`u16::MAX`].
57-
fn hash_to_curve<H>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Elem, InternalError>
57+
fn hash_to_curve<H>(input: &[&[u8]], dst: &[&[u8]]) -> Result<Self::Elem, InternalError>
5858
where
59-
H: Digest + BlockSizeUser,
59+
H: BlockSizeUser + Default + FixedOutput + HashMarker,
6060
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>;
6161

6262
/// Hashes a slice of pseudo-random bytes to a scalar
6363
///
6464
/// # Errors
6565
/// [`Error::Input`](crate::Error::Input) if the `input` is empty or longer
6666
/// then [`u16::MAX`].
67-
fn hash_to_scalar<H>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Scalar, InternalError>
67+
fn hash_to_scalar<H>(input: &[&[u8]], dst: &[&[u8]]) -> Result<Self::Scalar, InternalError>
6868
where
69-
H: Digest + BlockSizeUser,
69+
H: BlockSizeUser + Default + FixedOutput + HashMarker,
7070
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>;
7171

7272
/// Get the base point for the group

0 commit comments

Comments
 (0)