Compare commits

..
12 Commits
Author SHA1 Message Date
Kevin LewiandGitHub 40d81294db Publishing 0.5.0-pre.2 (#104) 2023-02-03 13:26:11 -08:00
daxpeddaandGitHub 8363d26f6f Bump curve25519-dalek to v4.0.0-rc.1 (#102) 2023-02-03 11:19:00 -08:00
daxpeddaandGitHub 5bce3e3206 Use explicit crate features (#100) 2023-02-01 11:37:47 -08:00
daxpeddaandGitHub 2787151e1d Update curve25519-dalek (#94) 2023-01-31 14:19:48 -08:00
daxpeddaandGitHub 0409db6f40 Depend on ProjectivePoint: ToEncodedPoint (#95) 2023-01-31 14:19:33 -08:00
daxpeddaandGitHub 74eaebe446 Fix Clippy (#96) 2023-01-31 10:31:13 -08:00
daxpeddaandGitHub c8de51672b Replace json with serde_json (#92) 2023-01-19 14:17:49 -08:00
daxpeddaandGitHub daa8dc048f Upgrade p256 to v0.12 (#90)
* Upgrade `p256` to v0.12

* Upgrade MSRV to 1.60
2023-01-19 11:11:56 -08:00
Kevin LewiandGitHub 2a351ceb4d Publishing 0.5.0-pre.1 (#88) 2022-12-19 13:17:58 -08:00
Kevin LewiandGitHub 8f60a10b8d Adding all-features CI test (#87) 2022-12-17 18:20:57 -08:00
daxpeddaandGitHub 1691125b09 Update curve25519-dalek to 4.0.0-pre.5 (#86)
* Update `curve25519-dalek`

* Improve documentation
2022-12-17 18:12:23 -08:00
daxpeddaandGitHub 6913b5deaa Fix Clippy (#85) 2022-12-10 14:21:04 -08:00
26 changed files with 211 additions and 393 deletions
+4 -5
View File
@@ -1,7 +1,6 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is dual-licensed under either the MIT license found in the
// LICENSE-MIT file in the root directory of this source tree or the Apache
// 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. You may select, at your option, one of the above-listed
// licenses.
// of this source tree.
+12 -13
View File
@@ -3,9 +3,8 @@ on:
push:
branches:
- main
- v0.4
pull_request:
types: [opened, reopened, synchronize]
types: [opened, repoened, synchronize]
jobs:
cargo-audit:
@@ -13,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Cache cargo-audit
uses: actions/cache@v4
uses: actions/cache@v3
with:
path: |
~/.cargo/.crates.toml
@@ -25,7 +24,7 @@ jobs:
run: cargo install cargo-audit
- name: Checkout sources
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Run cargo audit
run: cargo audit -D warnings
@@ -44,11 +43,11 @@ jobs:
- --features serde
toolchain:
- stable
- 1.65.0
- 1.60.0
name: test
steps:
- name: Checkout sources
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Install ${{ matrix.toolchain }} toolchain
uses: actions-rs/toolchain@v1
@@ -100,8 +99,8 @@ jobs:
- --features danger
- --features serde
steps:
- uses: actions/checkout@v4
- uses: hecrj/setup-rust-action@v2
- uses: actions/checkout@v3
- uses: hecrj/setup-rust-action@v1
- run: rustup target add ${{ matrix.target }}
- run: cargo build --verbose --target=${{ matrix.target }} --no-default-features ${{ matrix.frontend_feature }} ${{ matrix.backend_feature }}
@@ -111,7 +110,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Install stable toolchain
uses: actions-rs/toolchain@v1
@@ -141,7 +140,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Install nightly toolchain
uses: actions-rs/toolchain@v1
@@ -162,7 +161,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Cache
uses: actions/cache@v4
uses: actions/cache@v3
with:
path: |
~/.cargo/.crates.toml
@@ -171,10 +170,10 @@ jobs:
key: taplo
- name: Install Taplo
run: cargo install taplo-cli --locked
run: cargo install taplo-cli
- name: Checkout sources
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Run Taplo
run: taplo fmt --check
+1 -2
View File
@@ -10,10 +10,9 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
rust: [stable]
steps:
- uses: hecrj/setup-rust-action@v2
- uses: hecrj/setup-rust-action@v1
with:
rust-version: ${{ matrix.rust }}
- uses: actions/checkout@master
-4
View File
@@ -8,7 +8,3 @@ Cargo.lock
# These are backup files generated by rustfmt
**/*.rs.bk
# Editors
.idea
.vscode
+7 -4
View File
@@ -1,9 +1,12 @@
# Changelog
## 0.4.1 (September 24, 2024)
* Backport all non-protocol-breaking changes from versions 0.5+
* Fixes Rust 1.81+ compatibility, compatible with 0.4.0 (draft 11), incompatible with 0.5+ (final RFC)
* Updated dependencies
## 0.5.0-pre.2 (February 3, 2023)
* Increased MSRV to 1.60
* Updated p256 dependency to v0.12
* Updated curve25519-dalek dependency to 4.0.0-rc.1
## 0.5.0-pre.1 (December 19, 2022)
* Updated curve25519-dalek dependency to 4.0.0-pre.5
## 0.4.0 (September 15, 2022)
* Updated to be in sync with draft-irtf-cfrg-voprf-11, with
+1 -2
View File
@@ -27,5 +27,4 @@ outlined on that page and do not file a public issue.
## License
By contributing to voprf, you agree that your contributions will be
licensed under both the LICENSE-MIT and LICENSE-APACHE files in the root
directory of this source tree.
licensed under the LICENSE file in the root directory of this source tree.
+8 -16
View File
@@ -7,9 +7,9 @@ keywords = ["oprf"]
license = "MIT"
name = "voprf"
readme = "README.md"
repository = "https://github.com/facebook/voprf/"
rust-version = "1.65"
version = "0.4.1"
repository = "https://github.com/novifinancial/voprf/"
rust-version = "1.60"
version = "0.5.0-pre.2"
[features]
alloc = []
@@ -21,14 +21,14 @@ serde = ["generic-array/serde", "dep:serde"]
std = ["alloc"]
[dependencies]
curve25519-dalek = { version = "4", default-features = false, features = [
curve25519-dalek = { version = "=4.0.0-rc.1", default-features = false, features = [
"rand_core",
"zeroize",
], optional = true }
derive-where = { version = "1", features = ["zeroize-on-drop"] }
digest = "0.10"
displaydoc = { version = "0.2", default-features = false }
elliptic-curve = { version = "0.13", features = [
elliptic-curve = { version = "0.12", features = [
"hash2curve",
"sec1",
"voprf",
@@ -39,21 +39,13 @@ serde = { version = "1", default-features = false, features = [
"derive",
], optional = true }
sha2 = { version = "0.10", default-features = false, optional = true }
subtle = { version = "2.6", default-features = false }
zeroize = { version = "1.8", default-features = false }
subtle = { version = "2.3", default-features = false }
zeroize = { version = "1.5", default-features = false }
[dev-dependencies]
generic-array = { version = "0.14", features = ["more_lengths"] }
hex = "0.4"
p256 = { version = "0.13", default-features = false, features = [
"hash2curve",
"voprf",
] }
p384 = { version = "0.13", default-features = false, features = [
"hash2curve",
"voprf",
] }
p521 = { version = "0.13.3", default-features = false, features = [
p256 = { version = "0.12", default-features = false, features = [
"hash2curve",
"voprf",
] }
+12
View File
@@ -0,0 +1,12 @@
## License
Licensed under either of
* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall
be dual licensed as above, without any additional terms or conditions.
+4 -6
View File
@@ -1,4 +1,4 @@
# voprf ![Build Status](https://github.com/facebook/voprf/workflows/Rust%20CI/badge.svg)
# voprf ![Build Status](https://github.com/novifinancial/voprf/workflows/Rust%20CI/badge.svg)
An implementation of a (verifiable) oblivious pseudorandom function (VOPRF)
A VOPRF is a verifiable oblivious pseudorandom function, a protocol between a client and a server. The regular (non-verifiable) OPRF is also supported in this implementation.
@@ -16,12 +16,12 @@ Installation
Add the following line to the dependencies of your `Cargo.toml`:
```
voprf = "0.4.1"
voprf = "0.5.0-pre.2"
```
### Minimum Supported Rust Version
Rust **1.65** or higher.
Rust **1.60** or higher.
Contributors
------------
@@ -32,6 +32,4 @@ To learn more about contributing to this project, [see this document](./CONTRIBU
License
-------
This project is dual-licensed under either the [MIT license](./LICENSE-MIT)
or the [Apache License, Version 2.0](./LICENSE-APACHE).
You may select, at your option, one of the above-listed licenses.
This project is [licensed](./LICENSE) under either Apache 2.0 or MIT, at your option.
+9 -10
View File
@@ -1,15 +1,14 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is dual-licensed under either the MIT license found in the
// LICENSE-MIT file in the root directory of this source tree or the Apache
// 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. You may select, at your option, one of the above-listed
// licenses.
// of this source tree.
//! Defines the CipherSuite trait to specify the underlying primitives for VOPRF
use digest::core_api::BlockSizeUser;
use digest::{FixedOutput, HashMarker, OutputSizeUser};
use digest::{Digest, OutputSizeUser};
use elliptic_curve::VoprfParameters;
use generic_array::typenum::{IsLess, IsLessOrEqual, U256};
@@ -23,7 +22,7 @@ where
{
/// The ciphersuite identifier as dictated by
/// <https://datatracker.ietf.org/doc/draft-irtf-cfrg-voprf/>
const ID: &'static str;
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`].
@@ -31,17 +30,17 @@ where
/// The main hash function to use (for HKDF computations and hashing
/// transcripts).
type Hash: BlockSizeUser + Default + FixedOutput + HashMarker;
type Hash: BlockSizeUser + Digest;
}
impl<T: VoprfParameters> CipherSuite for T
where
T: Group,
T::Hash: BlockSizeUser + Default + FixedOutput + HashMarker,
T::Hash: BlockSizeUser + Digest,
<T::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<T::Hash as BlockSizeUser>::BlockSize>,
{
const ID: &'static str = T::ID;
const ID: u16 = T::ID;
type Group = T;
+31 -86
View File
@@ -1,21 +1,19 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is dual-licensed under either the MIT license found in the
// LICENSE-MIT file in the root directory of this source tree or the Apache
// 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. You may select, at your option, one of the above-listed
// licenses.
// of this source tree.
//! Common functionality between multiple OPRF modes.
use core::convert::TryFrom;
use core::ops::Add;
use derive_where::derive_where;
use digest::core_api::BlockSizeUser;
use digest::{Digest, Output, OutputSizeUser};
use generic_array::sequence::Concat;
use generic_array::typenum::{IsLess, IsLessOrEqual, Unsigned, U2, U256, U9};
use generic_array::typenum::{IsLess, IsLessOrEqual, Unsigned, U11, U2, U256};
use generic_array::{ArrayLength, GenericArray};
use rand_core::{CryptoRng, RngCore};
use subtle::ConstantTimeEq;
@@ -147,8 +145,8 @@ pub(crate) fn generate_proof<CS: CipherSuite, R: RngCore + CryptoRng>(
k: <CS::Group as Group>::Scalar,
a: <CS::Group as Group>::Elem,
b: <CS::Group as Group>::Elem,
cs: impl ExactSizeIterator<Item = <CS::Group as Group>::Elem>,
ds: impl ExactSizeIterator<Item = <CS::Group as Group>::Elem>,
cs: impl Iterator<Item = <CS::Group as Group>::Elem> + ExactSizeIterator,
ds: impl Iterator<Item = <CS::Group as Group>::Elem> + ExactSizeIterator,
mode: Mode,
) -> Result<Proof<CS>>
where
@@ -196,9 +194,9 @@ where
&STR_CHALLENGE,
];
let dst = Dst::new::<CS, _, _>(STR_HASH_TO_SCALAR, mode);
let dst = GenericArray::from(STR_HASH_TO_SCALAR).concat(create_context_string::<CS>(mode));
// This can't fail, the size of the `input` is known.
let c_scalar = CS::Group::hash_to_scalar::<CS::Hash>(&h2_input, &dst.as_dst()).unwrap();
let c_scalar = CS::Group::hash_to_scalar::<CS::Hash>(&h2_input, &dst).unwrap();
let s_scalar = r - &(c_scalar * &k);
Ok(Proof { c_scalar, s_scalar })
@@ -209,8 +207,8 @@ where
pub(crate) fn verify_proof<CS: CipherSuite>(
a: <CS::Group as Group>::Elem,
b: <CS::Group as Group>::Elem,
cs: impl ExactSizeIterator<Item = <CS::Group as Group>::Elem>,
ds: impl ExactSizeIterator<Item = <CS::Group as Group>::Elem>,
cs: impl Iterator<Item = <CS::Group as Group>::Elem> + ExactSizeIterator,
ds: impl Iterator<Item = <CS::Group as Group>::Elem> + ExactSizeIterator,
proof: &Proof<CS>,
mode: Mode,
) -> Result<()>
@@ -256,9 +254,9 @@ where
&STR_CHALLENGE,
];
let dst = Dst::new::<CS, _, _>(STR_HASH_TO_SCALAR, mode);
let dst = GenericArray::from(STR_HASH_TO_SCALAR).concat(create_context_string::<CS>(mode));
// This can't fail, the size of the `input` is known.
let c = CS::Group::hash_to_scalar::<CS::Hash>(&h2_input, &dst.as_dst()).unwrap();
let c = CS::Group::hash_to_scalar::<CS::Hash>(&h2_input, &dst).unwrap();
match c.ct_eq(&proof.c_scalar).into() {
true => Ok(()),
@@ -298,7 +296,7 @@ where
let len = u16::try_from(c_slice.len()).map_err(|_| Error::Batch)?;
// seedDST = "Seed-" || contextString
let seed_dst = Dst::new::<CS, _, _>(STR_SEED, mode);
let seed_dst = GenericArray::from(STR_SEED).concat(create_context_string::<CS>(mode));
// h1Input = I2OSP(len(Bm), 2) || Bm ||
// I2OSP(len(seedDST), 2) || seedDST
@@ -306,8 +304,8 @@ where
let seed = CS::Hash::new()
.chain_update(elem_len)
.chain_update(CS::Group::serialize_elem(b))
.chain_update(seed_dst.i2osp_2())
.chain_update_multi(&seed_dst.as_dst())
.chain_update(i2osp_2_array(&seed_dst))
.chain_update(seed_dst)
.finalize();
let seed_len = i2osp_2_array(&seed);
@@ -334,9 +332,9 @@ where
&STR_COMPOSITE,
];
let dst = Dst::new::<CS, _, _>(STR_HASH_TO_SCALAR, mode);
let dst = GenericArray::from(STR_HASH_TO_SCALAR).concat(create_context_string::<CS>(mode));
// This can't fail, the size of the `input` is known.
let di = CS::Group::hash_to_scalar::<CS::Hash>(&h2_input, &dst.as_dst()).unwrap();
let di = CS::Group::hash_to_scalar::<CS::Hash>(&h2_input, &dst).unwrap();
m = c * &di + &m;
z = match k_option {
Some(_) => z,
@@ -367,7 +365,8 @@ where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
let dst = Dst::new::<CS, _, _>(STR_DERIVE_KEYPAIR, mode);
let context_string = create_context_string::<CS>(mode);
let dst = GenericArray::from(STR_DERIVE_KEYPAIR).concat(context_string);
let info_len = i2osp_2(info.len()).map_err(|_| Error::DeriveKeyPair)?;
@@ -377,7 +376,7 @@ where
// || contextString)
let sk_s = CS::Group::hash_to_scalar::<CS::Hash>(
&[seed, &info_len, info, &counter.to_be_bytes()],
&dst.as_dst(),
&dst,
)
.map_err(|_| Error::DeriveKeyPair)?;
@@ -456,8 +455,8 @@ where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
let dst = Dst::new::<CS, _, _>(STR_HASH_TO_GROUP, mode);
CS::Group::hash_to_curve::<CS::Hash>(&[input], &dst.as_dst()).map_err(|_| Error::Input)
let dst = GenericArray::from(STR_HASH_TO_GROUP).concat(create_context_string::<CS>(mode));
CS::Group::hash_to_curve::<CS::Hash>(&[input], &dst).map_err(|_| Error::Input)
}
/// Internal function that finalizes the hash input for OPRF, VOPRF & POPRF.
@@ -498,70 +497,16 @@ where
.finalize())
}
pub(crate) struct Dst<L: ArrayLength<u8>> {
dst_1: GenericArray<u8, L>,
dst_2: [u8; 2],
}
impl<L: ArrayLength<u8>> Dst<L> {
pub(crate) fn new<CS: CipherSuite, T, TL>(par_1: T, mode: Mode) -> Self
where
T: Into<GenericArray<u8, TL>>,
TL: ArrayLength<u8> + Add<U9, Output = L>,
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
let par_1 = par_1.into();
// Generates the contextString parameter as defined in
// <https://datatracker.ietf.org/doc/draft-irtf-cfrg-voprf/>
let par_2 = GenericArray::from(STR_VOPRF).concat([mode.to_u8()].into());
// See <https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-11.html#section-4.1>
let cs_id_u16: u16 = match CS::ID {
"ristretto255-SHA512" => 0x0001,
"decaf448-SHAKE256" => 0x0002,
"P256-SHA256" => 0x0003,
"P384-SHA384" => 0x0004,
"P521-SHA512" => 0x0005,
_ => panic!("Incompatible ciphersuite: {}", CS::ID),
};
let dst_1 = par_1.concat(par_2);
let dst_2 = cs_id_u16.to_be_bytes();
assert!(
L::USIZE + 2 <= u16::MAX.into(),
"constructed DST longer then {}",
u16::MAX
);
Self { dst_1, dst_2 }
}
pub(crate) fn as_dst(&self) -> [&[u8]; 2] {
[&self.dst_1, &self.dst_2]
}
pub(crate) fn i2osp_2(&self) -> [u8; 2] {
u16::try_from(L::USIZE + 2).unwrap().to_be_bytes()
}
}
trait DigestExt {
fn chain_update_multi(self, data: &[&[u8]]) -> Self;
}
impl<T> DigestExt for T
/// Generates the contextString parameter as defined in
/// <https://datatracker.ietf.org/doc/draft-irtf-cfrg-voprf/>
pub(crate) fn create_context_string<CS: CipherSuite>(mode: Mode) -> GenericArray<u8, U11>
where
T: Digest,
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
fn chain_update_multi(mut self, datas: &[&[u8]]) -> Self {
for data in datas {
self.update(data)
}
self
}
GenericArray::from(STR_VOPRF)
.concat([mode.to_u8()].into())
.concat(CS::ID.to_be_bytes().into())
}
///////////////////////
+4 -5
View File
@@ -1,10 +1,9 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is dual-licensed under either the MIT license found in the
// LICENSE-MIT file in the root directory of this source tree or the Apache
// 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. You may select, at your option, one of the above-listed
// licenses.
// of this source tree.
//! Errors which are produced during an execution of the protocol
+15 -16
View File
@@ -1,18 +1,17 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is dual-licensed under either the MIT license found in the
// LICENSE-MIT file in the root directory of this source tree or the Apache
// 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. You may select, at your option, one of the above-listed
// licenses.
// of this source tree.
use digest::core_api::BlockSizeUser;
use digest::{FixedOutput, HashMarker};
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, Field, FieldBytesSize, Group as _, ProjectivePoint, PublicKey, Scalar, SecretKey,
AffinePoint, Field, FieldSize, Group as _, ProjectivePoint, PublicKey, Scalar, SecretKey,
};
use generic_array::typenum::{IsLess, IsLessOrEqual, U256};
use generic_array::GenericArray;
@@ -25,32 +24,32 @@ impl<C> Group for C
where
C: GroupDigest,
ProjectivePoint<Self>: CofactorGroup + ToEncodedPoint<Self>,
FieldBytesSize<Self>: ModulusSize,
FieldSize<Self>: ModulusSize,
AffinePoint<Self>: FromEncodedPoint<Self> + ToEncodedPoint<Self>,
Scalar<Self>: FromOkm,
{
type Elem = ProjectivePoint<Self>;
type ElemLen = <FieldBytesSize<Self> as ModulusSize>::CompressedPointSize;
type ElemLen = <FieldSize<Self> as ModulusSize>::CompressedPointSize;
type Scalar = Scalar<Self>;
type ScalarLen = FieldBytesSize<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<H>(input: &[&[u8]], dst: &[&[u8]]) -> Result<Self::Elem, InternalError>
fn hash_to_curve<H>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Elem, InternalError>
where
H: BlockSizeUser + Default + FixedOutput + HashMarker,
H: Digest + BlockSizeUser,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>,
{
Self::hash_from_bytes::<ExpandMsgXmd<H>>(input, dst).map_err(|_| InternalError::Input)
}
// Implements the `HashToScalar()` function
fn hash_to_scalar<H>(input: &[&[u8]], dst: &[&[u8]]) -> Result<Self::Scalar, InternalError>
fn hash_to_scalar<H>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Scalar, InternalError>
where
H: BlockSizeUser + Default + FixedOutput + HashMarker,
H: Digest + BlockSizeUser,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>,
{
<Self as GroupDigest>::hash_to_scalar::<ExpandMsgXmd<H>>(input, dst)
@@ -93,7 +92,7 @@ where
#[cfg(test)]
fn zero_scalar() -> Self::Scalar {
Scalar::<Self>::ZERO
Scalar::<Self>::zero()
}
fn serialize_scalar(scalar: Self::Scalar) -> GenericArray<u8, Self::ScalarLen> {
@@ -101,7 +100,7 @@ where
}
fn deserialize_scalar(scalar_bits: &[u8]) -> Result<Self::Scalar> {
SecretKey::<Self>::from_slice(scalar_bits)
SecretKey::<Self>::from_be_bytes(scalar_bits)
.map(|secret_key| *secret_key.to_nonzero_scalar())
.map_err(|_| Error::Deserialization)
}
+9 -10
View File
@@ -1,10 +1,9 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is dual-licensed under either the MIT license found in the
// LICENSE-MIT file in the root directory of this source tree or the Apache
// 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. You may select, at your option, one of the above-listed
// licenses.
// of this source tree.
//! Defines the Group trait to specify the underlying prime order group
@@ -15,7 +14,7 @@ mod ristretto;
use core::ops::{Add, Mul, Sub};
use digest::core_api::BlockSizeUser;
use digest::{FixedOutput, HashMarker};
use digest::Digest;
use generic_array::typenum::{IsLess, IsLessOrEqual, U256};
use generic_array::{ArrayLength, GenericArray};
use rand_core::{CryptoRng, RngCore};
@@ -55,9 +54,9 @@ pub trait Group {
/// # Errors
/// [`Error::Input`](crate::Error::Input) if the `input` is empty or longer
/// then [`u16::MAX`].
fn hash_to_curve<H>(input: &[&[u8]], dst: &[&[u8]]) -> Result<Self::Elem, InternalError>
fn hash_to_curve<H>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Elem, InternalError>
where
H: BlockSizeUser + Default + FixedOutput + HashMarker,
H: Digest + BlockSizeUser,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>;
/// Hashes a slice of pseudo-random bytes to a scalar
@@ -65,9 +64,9 @@ pub trait Group {
/// # 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::Scalar, InternalError>
fn hash_to_scalar<H>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Scalar, InternalError>
where
H: BlockSizeUser + Default + FixedOutput + HashMarker,
H: Digest + BlockSizeUser,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>;
/// Get the base point for the group
+10 -11
View File
@@ -1,17 +1,16 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is dual-licensed under either the MIT license found in the
// LICENSE-MIT file in the root directory of this source tree or the Apache
// 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. You may select, at your option, one of the above-listed
// licenses.
// of this source tree.
use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT;
use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint};
use curve25519_dalek::scalar::Scalar;
use curve25519_dalek::traits::Identity;
use digest::core_api::BlockSizeUser;
use digest::{FixedOutput, HashMarker};
use digest::Digest;
use elliptic_curve::hash2curve::{ExpandMsg, ExpandMsgXmd, Expander};
use generic_array::typenum::{IsLess, IsLessOrEqual, U256, U32, U64};
use generic_array::GenericArray;
@@ -27,7 +26,7 @@ pub struct Ristretto255;
#[cfg(feature = "ristretto255-ciphersuite")]
impl crate::CipherSuite for Ristretto255 {
const ID: &'static str = "ristretto255-SHA512";
const ID: u16 = 0x0001;
type Group = Ristretto255;
@@ -45,9 +44,9 @@ 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<H>(input: &[&[u8]], dst: &[&[u8]]) -> Result<Self::Elem, InternalError>
fn hash_to_curve<H>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Elem, InternalError>
where
H: BlockSizeUser + Default + FixedOutput + HashMarker,
H: Digest + BlockSizeUser,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>,
{
let mut uniform_bytes = GenericArray::<_, U64>::default();
@@ -60,9 +59,9 @@ 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<H>(input: &[&[u8]], dst: &[&[u8]]) -> Result<Self::Scalar, InternalError>
fn hash_to_scalar<H>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Scalar, InternalError>
where
H: BlockSizeUser + Default + FixedOutput + HashMarker,
H: Digest + BlockSizeUser,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>,
{
let mut uniform_bytes = GenericArray::<_, U64>::default();
+4 -13
View File
@@ -1,10 +1,9 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is dual-licensed under either the MIT license found in the
// LICENSE-MIT file in the root directory of this source tree or the Apache
// 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. You may select, at your option, one of the above-listed
// licenses.
// of this source tree.
//! Includes a series of tests for the group implementations
@@ -16,8 +15,6 @@ use crate::{Error, Group, Result};
#[test]
fn test_group_properties() -> Result<()> {
use p256::NistP256;
use p384::NistP384;
use p521::NistP521;
#[cfg(feature = "ristretto255")]
{
@@ -30,12 +27,6 @@ fn test_group_properties() -> Result<()> {
test_identity_element_error::<NistP256>()?;
test_zero_scalar_error::<NistP256>()?;
test_identity_element_error::<NistP384>()?;
test_zero_scalar_error::<NistP384>()?;
test_identity_element_error::<NistP521>()?;
test_zero_scalar_error::<NistP521>()?;
Ok(())
}
+4 -5
View File
@@ -1,10 +1,9 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is dual-licensed under either the MIT license found in the
// LICENSE-MIT file in the root directory of this source tree or the Apache
// 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. You may select, at your option, one of the above-listed
// licenses.
// of this source tree.
//! An implementation of a verifiable oblivious pseudorandom function (VOPRF)
//!
+11 -26
View File
@@ -1,10 +1,9 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is dual-licensed under either the MIT license found in the
// LICENSE-MIT file in the root directory of this source tree or the Apache
// 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. You may select, at your option, one of the above-listed
// licenses.
// of this source tree.
//! Contains the main OPRF API
@@ -292,10 +291,11 @@ where
mod tests {
use core::ptr;
use generic_array::sequence::Concat;
use rand::rngs::OsRng;
use super::*;
use crate::common::{Dst, STR_HASH_TO_GROUP};
use crate::common::{create_context_string, STR_HASH_TO_GROUP};
use crate::Group;
fn prf<CS: CipherSuite>(
@@ -308,8 +308,8 @@ mod tests {
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
let dst = Dst::new::<CS, _, _>(STR_HASH_TO_GROUP, mode);
let point = CS::Group::hash_to_curve::<CS::Hash>(&[input], &dst.as_dst()).unwrap();
let dst = GenericArray::from(STR_HASH_TO_GROUP).concat(create_context_string::<CS>(mode));
let point = CS::Group::hash_to_curve::<CS::Hash>(&[input], &dst).unwrap();
let res = point * &key;
@@ -348,8 +348,9 @@ mod tests {
.finalize(&input, &EvaluationElement(client_blind_result.message.0))
.unwrap();
let dst = Dst::new::<CS, _, _>(STR_HASH_TO_GROUP, Mode::Oprf);
let point = CS::Group::hash_to_curve::<CS::Hash>(&[&input], &dst.as_dst()).unwrap();
let dst =
GenericArray::from(STR_HASH_TO_GROUP).concat(create_context_string::<CS>(Mode::Oprf));
let point = CS::Group::hash_to_curve::<CS::Hash>(&[&input], &dst).unwrap();
let res2 = finalize_after_unblind::<CS, _, _>(iter::once((input.as_ref(), point)), &[])
.next()
.unwrap()
@@ -426,8 +427,6 @@ mod tests {
#[test]
fn test_functionality() -> Result<()> {
use p256::NistP256;
use p384::NistP384;
use p521::NistP521;
#[cfg(feature = "ristretto255")]
{
@@ -448,20 +447,6 @@ mod tests {
zeroize_oprf_client::<NistP256>();
zeroize_oprf_server::<NistP256>();
base_retrieval::<NistP384>();
base_inversion_unsalted::<NistP384>();
server_evaluate::<NistP384>();
zeroize_oprf_client::<NistP384>();
zeroize_oprf_server::<NistP384>();
base_retrieval::<NistP521>();
base_inversion_unsalted::<NistP521>();
server_evaluate::<NistP521>();
zeroize_oprf_client::<NistP521>();
zeroize_oprf_server::<NistP521>();
Ok(())
}
}
+21 -33
View File
@@ -1,10 +1,9 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is dual-licensed under either the MIT license found in the
// LICENSE-MIT file in the root directory of this source tree or the Apache
// 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. You may select, at your option, one of the above-listed
// licenses.
// of this source tree.
//! Contains the main POPRF API
@@ -15,14 +14,16 @@ use core::iter::{self, Map, Repeat, Zip};
use derive_where::derive_where;
use digest::core_api::BlockSizeUser;
use digest::{Digest, Output, OutputSizeUser};
use generic_array::sequence::Concat;
use generic_array::typenum::{IsLess, IsLessOrEqual, Unsigned, U256};
use generic_array::GenericArray;
use rand_core::{CryptoRng, RngCore};
use crate::common::{
derive_keypair, deterministic_blind_unchecked, generate_proof, hash_to_group, i2osp_2,
server_evaluate_hash_input, verify_proof, BlindedElement, Dst, EvaluationElement, Mode,
PreparedEvaluationElement, Proof, STR_FINALIZE, STR_HASH_TO_SCALAR, STR_INFO,
create_context_string, derive_keypair, deterministic_blind_unchecked, generate_proof,
hash_to_group, i2osp_2, server_evaluate_hash_input, verify_proof, BlindedElement,
EvaluationElement, Mode, PreparedEvaluationElement, Proof, STR_FINALIZE, STR_HASH_TO_SCALAR,
STR_INFO,
};
#[cfg(feature = "serde")]
use crate::serialization::serde::{Element, Scalar};
@@ -615,9 +616,10 @@ where
let info_len = i2osp_2(info.len()).map_err(|_| Error::Info)?;
let framed_info = [STR_INFO.as_slice(), &info_len, info];
let dst = Dst::new::<CS, _, _>(STR_HASH_TO_SCALAR, Mode::Poprf);
let dst =
GenericArray::from(STR_HASH_TO_SCALAR).concat(create_context_string::<CS>(Mode::Poprf));
// This can't fail, the size of the `input` is known.
let m = CS::Group::hash_to_scalar::<CS::Hash>(&framed_info, &dst.as_dst()).unwrap();
let m = CS::Group::hash_to_scalar::<CS::Hash>(&framed_info, &dst).unwrap();
let t = CS::Group::base_elem() * &m;
let tweaked_key = t + &pk;
@@ -652,9 +654,10 @@ where
let info_len = i2osp_2(info.len()).map_err(|_| Error::Info)?;
let framed_info = [STR_INFO.as_slice(), &info_len, info];
let dst = Dst::new::<CS, _, _>(STR_HASH_TO_SCALAR, Mode::Poprf);
let dst =
GenericArray::from(STR_HASH_TO_SCALAR).concat(create_context_string::<CS>(Mode::Poprf));
// This can't fail, the size of the `input` is known.
let m = CS::Group::hash_to_scalar::<CS::Hash>(&framed_info, &dst.as_dst()).unwrap();
let m = CS::Group::hash_to_scalar::<CS::Hash>(&framed_info, &dst).unwrap();
let t = sk + &m;
@@ -720,7 +723,7 @@ where
)?;
Ok(blinds
.zip(messages)
.zip(messages.into_iter())
.map(|(blind, x)| x.0 * &CS::Group::invert_scalar(blind)))
}
@@ -807,8 +810,8 @@ mod tests {
{
let t = compute_tweak::<CS>(key, Some(info)).unwrap();
let dst = Dst::new::<CS, _, _>(STR_HASH_TO_GROUP, mode);
let point = CS::Group::hash_to_curve::<CS::Hash>(&[input], &dst.as_dst()).unwrap();
let dst = GenericArray::from(STR_HASH_TO_GROUP).concat(create_context_string::<CS>(mode));
let point = CS::Group::hash_to_curve::<CS::Hash>(&[input], &dst).unwrap();
// evaluatedElement = G.ScalarInverse(t) * blindedElement
let res = point * &CS::Group::invert_scalar(t);
@@ -861,9 +864,10 @@ mod tests {
.blind_evaluate(&mut rng, &client_blind_result.message, Some(info))
.unwrap();
let wrong_pk = {
let dst = Dst::new::<CS, _, _>(STR_HASH_TO_GROUP, Mode::Oprf);
let dst = GenericArray::from(STR_HASH_TO_GROUP)
.concat(create_context_string::<CS>(Mode::Oprf));
// Choose a group element that is unlikely to be the right public key
CS::Group::hash_to_curve::<CS::Hash>(&[b"msg"], &dst.as_dst()).unwrap()
CS::Group::hash_to_curve::<CS::Hash>(&[b"msg"], &dst).unwrap()
};
let client_finalize_result = client_blind_result.state.finalize(
input,
@@ -966,8 +970,6 @@ mod tests {
#[test]
fn test_functionality() -> Result<()> {
use p256::NistP256;
use p384::NistP384;
use p521::NistP521;
#[cfg(feature = "ristretto255")]
{
@@ -988,20 +990,6 @@ mod tests {
zeroize_verifiable_client::<NistP256>();
zeroize_verifiable_server::<NistP256>();
verifiable_retrieval::<NistP384>();
verifiable_bad_public_key::<NistP384>();
verifiable_server_evaluate::<NistP384>();
zeroize_verifiable_client::<NistP384>();
zeroize_verifiable_server::<NistP384>();
verifiable_retrieval::<NistP521>();
verifiable_bad_public_key::<NistP521>();
verifiable_server_evaluate::<NistP521>();
zeroize_verifiable_client::<NistP521>();
zeroize_verifiable_server::<NistP521>();
Ok(())
}
}
+6 -9
View File
@@ -1,10 +1,9 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is dual-licensed under either the MIT license found in the
// LICENSE-MIT file in the root directory of this source tree or the Apache
// 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. You may select, at your option, one of the above-listed
// licenses.
// of this source tree.
//! Handles the serialization of each of the components used in the VOPRF
//! protocol
@@ -307,11 +306,11 @@ fn deserialize_scalar<G: Group>(input: &mut &[u8]) -> Result<G::Scalar> {
}
trait SliceExt {
fn take_ext<'a>(self: &mut &'a Self, take: usize) -> Option<&'a Self>;
fn take_ext(self: &mut &Self, take: usize) -> Option<&Self>;
}
impl<T> SliceExt for [T] {
fn take_ext<'a>(self: &mut &'a Self, take: usize) -> Option<&'a Self> {
fn take_ext(self: &mut &Self, take: usize) -> Option<&Self> {
if take > self.len() {
return None;
}
@@ -390,8 +389,6 @@ mod test {
}
let _ = $item::<p256::NistP256>::deserialize(&$bytes[..]);
let _ = $item::<p384::NistP384>::deserialize(&$bytes[..]);
let _ = $item::<p521::NistP521>::deserialize(&$bytes[..]);
};
}
+5 -6
View File
@@ -1,13 +1,12 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is dual-licensed under either the MIT license found in the
// LICENSE-MIT file in the root directory of this source tree or the Apache
// 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. You may select, at your option, one of the above-listed
// licenses.
// of this source tree.
//! The VOPRF test vectors taken from:
//! https://github.com/cfrg/draft-irtf-cfrg-voprf/blob/dff20b461c0de23fcd521116f3d058cfa5b80b90/draft-irtf-cfrg-voprf.md
//! https://github.com/cfrg/draft-irtf-cfrg-voprf/blob/master/draft-irtf-cfrg-voprf.md
pub(crate) const VECTORS: &str = r#"
## OPRF(ristretto255, SHA-512)
+4 -5
View File
@@ -1,10 +1,9 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is dual-licensed under either the MIT license found in the
// LICENSE-MIT file in the root directory of this source tree or the Apache
// 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. You may select, at your option, one of the above-listed
// licenses.
// of this source tree.
use alloc::vec::Vec;
use core::cmp::min;
+4 -5
View File
@@ -1,10 +1,9 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is dual-licensed under either the MIT license found in the
// LICENSE-MIT file in the root directory of this source tree or the Apache
// 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. You may select, at your option, one of the above-listed
// licenses.
// of this source tree.
mod cfrg_vectors;
mod mock_rng;
+4 -5
View File
@@ -1,10 +1,9 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is dual-licensed under either the MIT license found in the
// LICENSE-MIT file in the root directory of this source tree or the Apache
// 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. You may select, at your option, one of the above-listed
// licenses.
// of this source tree.
use alloc::string::{String, ToString};
use alloc::vec::Vec;
+4 -61
View File
@@ -1,10 +1,9 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is dual-licensed under either the MIT license found in the
// LICENSE-MIT file in the root directory of this source tree or the Apache
// 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. You may select, at your option, one of the above-listed
// licenses.
// of this source tree.
use alloc::string::String;
use alloc::vec;
@@ -88,8 +87,6 @@ macro_rules! json_to_test_vectors {
#[test]
fn test_vectors() -> Result<()> {
use p256::NistP256;
use p384::NistP384;
use p521::NistP521;
let rfc: Value = serde_json::from_str(rfc_to_json(super::cfrg_vectors::VECTORS).as_str())
.expect("Could not parse json");
@@ -162,60 +159,6 @@ fn test_vectors() -> Result<()> {
test_poprf_finalize::<NistP256>(&p256_poprf_tvs)?;
test_poprf_evaluate::<NistP256>(&p256_poprf_tvs)?;
let p384_oprf_tvs =
json_to_test_vectors!(rfc, String::from("P-384, SHA-384"), String::from("OPRF"));
assert_ne!(p384_oprf_tvs.len(), 0);
test_oprf_seed_to_key::<NistP384>(&p384_oprf_tvs)?;
test_oprf_blind::<NistP384>(&p384_oprf_tvs)?;
test_oprf_blind_evaluate::<NistP384>(&p384_oprf_tvs)?;
test_oprf_finalize::<NistP384>(&p384_oprf_tvs)?;
test_oprf_evaluate::<NistP384>(&p384_oprf_tvs)?;
let p384_voprf_tvs =
json_to_test_vectors!(rfc, String::from("P-384, SHA-384"), String::from("VOPRF"));
assert_ne!(p384_voprf_tvs.len(), 0);
test_voprf_seed_to_key::<NistP384>(&p384_voprf_tvs)?;
test_voprf_blind::<NistP384>(&p384_voprf_tvs)?;
test_voprf_blind_evaluate::<NistP384>(&p384_voprf_tvs)?;
test_voprf_finalize::<NistP384>(&p384_voprf_tvs)?;
test_voprf_evaluate::<NistP384>(&p384_voprf_tvs)?;
let p384_poprf_tvs =
json_to_test_vectors!(rfc, String::from("P-384, SHA-384"), String::from("POPRF"));
assert_ne!(p384_poprf_tvs.len(), 0);
test_poprf_seed_to_key::<NistP384>(&p384_poprf_tvs)?;
test_poprf_blind::<NistP384>(&p384_poprf_tvs)?;
test_poprf_blind_evaluate::<NistP384>(&p384_poprf_tvs)?;
test_poprf_finalize::<NistP384>(&p384_poprf_tvs)?;
test_poprf_evaluate::<NistP384>(&p384_poprf_tvs)?;
let p521_oprf_tvs =
json_to_test_vectors!(rfc, String::from("P-521, SHA-512"), String::from("OPRF"));
assert_ne!(p521_oprf_tvs.len(), 0);
test_oprf_seed_to_key::<NistP521>(&p521_oprf_tvs)?;
test_oprf_blind::<NistP521>(&p521_oprf_tvs)?;
test_oprf_blind_evaluate::<NistP521>(&p521_oprf_tvs)?;
test_oprf_finalize::<NistP521>(&p521_oprf_tvs)?;
test_oprf_evaluate::<NistP521>(&p521_oprf_tvs)?;
let p521_voprf_tvs =
json_to_test_vectors!(rfc, String::from("P-521, SHA-512"), String::from("VOPRF"));
assert_ne!(p521_voprf_tvs.len(), 0);
test_voprf_seed_to_key::<NistP521>(&p521_voprf_tvs)?;
test_voprf_blind::<NistP521>(&p521_voprf_tvs)?;
test_voprf_blind_evaluate::<NistP521>(&p521_voprf_tvs)?;
test_voprf_finalize::<NistP521>(&p521_voprf_tvs)?;
test_voprf_evaluate::<NistP521>(&p521_voprf_tvs)?;
let p521_poprf_tvs =
json_to_test_vectors!(rfc, String::from("P-521, SHA-512"), String::from("POPRF"));
assert_ne!(p521_poprf_tvs.len(), 0);
test_poprf_seed_to_key::<NistP521>(&p521_poprf_tvs)?;
test_poprf_blind::<NistP521>(&p521_poprf_tvs)?;
test_poprf_blind_evaluate::<NistP521>(&p521_poprf_tvs)?;
test_poprf_finalize::<NistP521>(&p521_poprf_tvs)?;
test_poprf_evaluate::<NistP521>(&p521_poprf_tvs)?;
Ok(())
}
+17 -35
View File
@@ -1,10 +1,9 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is dual-licensed under either the MIT license found in the
// LICENSE-MIT file in the root directory of this source tree or the Apache
// 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. You may select, at your option, one of the above-listed
// licenses.
// of this source tree.
//! Contains the main VOPRF API
@@ -161,7 +160,7 @@ where
///
/// The resulting messages can each fail individually with [`Error::Input`]
/// if the `input` is empty or longer then [`u16::MAX`].
pub fn batch_finalize<'a, I, II, IC, IM>(
pub fn batch_finalize<'a, I: 'a, II, IC, IM>(
inputs: &'a II,
clients: &'a IC,
messages: &'a IM,
@@ -170,7 +169,7 @@ where
) -> Result<VoprfClientBatchFinalizeResult<'a, CS, I, II, IC, IM>>
where
CS: 'a,
I: 'a + AsRef<[u8]>,
I: AsRef<[u8]>,
&'a II: 'a + IntoIterator<Item = I>,
<&'a II as IntoIterator>::IntoIter: ExactSizeIterator,
&'a IC: 'a + IntoIterator<Item = &'a VoprfClient<CS>>,
@@ -537,7 +536,7 @@ where
)?;
Ok(blinds
.zip(messages)
.zip(messages.into_iter())
.map(|(blind, x)| x.0 * &CS::Group::invert_scalar(blind)))
}
@@ -588,12 +587,13 @@ mod tests {
use ::alloc::vec;
use ::alloc::vec::Vec;
use generic_array::sequence::Concat;
use generic_array::typenum::Sum;
use generic_array::ArrayLength;
use rand::rngs::OsRng;
use super::*;
use crate::common::{Dst, STR_HASH_TO_GROUP};
use crate::common::{create_context_string, STR_HASH_TO_GROUP};
use crate::Group;
fn prf<CS: CipherSuite>(
@@ -605,8 +605,8 @@ mod tests {
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
let dst = Dst::new::<CS, _, _>(STR_HASH_TO_GROUP, mode);
let point = CS::Group::hash_to_curve::<CS::Hash>(&[input], &dst.as_dst()).unwrap();
let dst = GenericArray::from(STR_HASH_TO_GROUP).concat(create_context_string::<CS>(mode));
let point = CS::Group::hash_to_curve::<CS::Hash>(&[input], &dst).unwrap();
let res = point * &key;
@@ -718,9 +718,10 @@ mod tests {
.unwrap();
let messages: Vec<_> = messages.collect();
let wrong_pk = {
let dst = Dst::new::<CS, _, _>(STR_HASH_TO_GROUP, Mode::Oprf);
let dst = GenericArray::from(STR_HASH_TO_GROUP)
.concat(create_context_string::<CS>(Mode::Oprf));
// Choose a group element that is unlikely to be the right public key
CS::Group::hash_to_curve::<CS::Hash>(&[b"msg"], &dst.as_dst()).unwrap()
CS::Group::hash_to_curve::<CS::Hash>(&[b"msg"], &dst).unwrap()
};
let client_finalize_result =
VoprfClient::batch_finalize(&inputs, &client_states, &messages, &proof, wrong_pk);
@@ -738,9 +739,10 @@ mod tests {
let server = VoprfServer::<CS>::new(&mut rng).unwrap();
let server_result = server.blind_evaluate(&mut rng, &client_blind_result.message);
let wrong_pk = {
let dst = Dst::new::<CS, _, _>(STR_HASH_TO_GROUP, Mode::Oprf);
let dst = GenericArray::from(STR_HASH_TO_GROUP)
.concat(create_context_string::<CS>(Mode::Oprf));
// Choose a group element that is unlikely to be the right public key
CS::Group::hash_to_curve::<CS::Hash>(&[b"msg"], &dst.as_dst()).unwrap()
CS::Group::hash_to_curve::<CS::Hash>(&[b"msg"], &dst).unwrap()
};
let client_finalize_result = client_blind_result.state.finalize(
input,
@@ -835,8 +837,6 @@ mod tests {
#[test]
fn test_functionality() -> Result<()> {
use p256::NistP256;
use p384::NistP384;
use p521::NistP521;
#[cfg(feature = "ristretto255")]
{
@@ -861,24 +861,6 @@ mod tests {
zeroize_voprf_client::<NistP256>();
zeroize_voprf_server::<NistP256>();
verifiable_retrieval::<NistP384>();
verifiable_batch_retrieval::<NistP384>();
verifiable_bad_public_key::<NistP384>();
verifiable_batch_bad_public_key::<NistP384>();
verifiable_server_evaluate::<NistP384>();
zeroize_voprf_client::<NistP384>();
zeroize_voprf_server::<NistP384>();
verifiable_retrieval::<NistP521>();
verifiable_batch_retrieval::<NistP521>();
verifiable_bad_public_key::<NistP521>();
verifiable_batch_bad_public_key::<NistP521>();
verifiable_server_evaluate::<NistP521>();
zeroize_voprf_client::<NistP521>();
zeroize_voprf_server::<NistP521>();
Ok(())
}
}