Adding VOPRF draft's test vectors (#95)

Co-authored-by: Kevin Lewi <[email protected]>
This commit is contained in:
Kevin Lewi
2020-12-04 13:19:29 -08:00
committed by GitHub
co-authored by Kevin Lewi
parent 6f5a1fc6aa
commit 9f414d4a82
8 changed files with 242 additions and 57 deletions
+8 -8
View File
@@ -14,7 +14,7 @@ use opaque_ke::{
oprf::{blind_shim, evaluate_shim, unblind_and_finalize_shim},
};
use rand::{prelude::ThreadRng, thread_rng};
use sha2::Sha256;
use sha2::{Sha256, Sha512};
fn oprf1(c: &mut Criterion) {
let mut csprng: ThreadRng = thread_rng();
@@ -22,7 +22,7 @@ fn oprf1(c: &mut Criterion) {
c.bench_function("blind with Ristretto", move |b| {
b.iter(|| {
blind_shim::<_, RistrettoPoint>(&input[..], &mut csprng).unwrap();
blind_shim::<_, RistrettoPoint, Sha512>(&input[..], &mut csprng).unwrap();
})
});
}
@@ -33,7 +33,7 @@ fn oprf1_edwards(c: &mut Criterion) {
c.bench_function("blind with Edwards", move |b| {
b.iter(|| {
blind_shim::<_, EdwardsPoint>(&input[..], &mut csprng).unwrap();
blind_shim::<_, EdwardsPoint, Sha256>(&input[..], &mut csprng).unwrap();
})
});
}
@@ -42,7 +42,7 @@ fn oprf2(c: &mut Criterion) {
let mut csprng: ThreadRng = thread_rng();
let input = b"hunter2";
let (_, alpha) = blind_shim::<_, RistrettoPoint>(&input[..], &mut csprng).unwrap();
let (_, alpha) = blind_shim::<_, RistrettoPoint, Sha512>(&input[..], &mut csprng).unwrap();
let salt_bytes = arr![
u8; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32,
@@ -60,7 +60,7 @@ fn oprf2_edwards(c: &mut Criterion) {
let mut csprng: ThreadRng = thread_rng();
let input = b"hunter2";
let (_, alpha) = blind_shim::<_, EdwardsPoint>(&input[..], &mut csprng).unwrap();
let (_, alpha) = blind_shim::<_, EdwardsPoint, Sha256>(&input[..], &mut csprng).unwrap();
let salt_bytes = arr![
u8; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32,
@@ -78,7 +78,7 @@ fn oprf3(c: &mut Criterion) {
let mut csprng: ThreadRng = thread_rng();
let input = b"hunter2";
let (token, alpha) = blind_shim::<_, RistrettoPoint>(&input[..], &mut csprng).unwrap();
let (token, alpha) = blind_shim::<_, RistrettoPoint, Sha512>(&input[..], &mut csprng).unwrap();
let salt_bytes = arr![
u8; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32,
@@ -88,7 +88,7 @@ fn oprf3(c: &mut Criterion) {
c.bench_function("unblind_and_finalize with Ristretto", move |b| {
b.iter(|| {
let _res = unblind_and_finalize_shim::<RistrettoPoint, Sha256>(&token, beta).unwrap();
let _res = unblind_and_finalize_shim::<RistrettoPoint, Sha512>(&token, beta).unwrap();
})
});
}
@@ -97,7 +97,7 @@ fn oprf3_edwards(c: &mut Criterion) {
let mut csprng: ThreadRng = thread_rng();
let input = b"hunter2";
let (token, alpha) = blind_shim::<_, EdwardsPoint>(&input[..], &mut csprng).unwrap();
let (token, alpha) = blind_shim::<_, EdwardsPoint, Sha256>(&input[..], &mut csprng).unwrap();
let salt_bytes = arr![
u8; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32,
+1 -1
View File
@@ -29,7 +29,7 @@ pub trait Group: Sized + for<'a> Mul<&'a <Self as Group>::Scalar, Output = Self>
type Scalar: Zeroize;
/// The byte length necessary to represent scalars
type ScalarLen: ArrayLength<u8>;
/// Return a scalat from its fixed-length bytes representation
/// Return a scalar from its fixed-length bytes representation
fn from_scalar_slice(
scalar_bits: &GenericArray<u8, Self::ScalarLen>,
) -> Result<Self::Scalar, InternalPakeError>;
+10 -9
View File
@@ -15,7 +15,6 @@ use digest::{BlockInput, Digest};
use generic_array::typenum::Unsigned;
use generic_array::GenericArray;
use hkdf::Hkdf;
use sha2::Sha256;
/// A subtrait of Group specifying how to hash a password into a point
pub trait GroupWithMapToCurve: Group {
@@ -24,7 +23,7 @@ pub trait GroupWithMapToCurve: Group {
const SUITE_ID: usize;
/// transforms a password and domain separation tag (DST) into a curve point
fn map_to_curve(msg: &[u8], dst: &[u8]) -> Result<Self, InternalPakeError>;
fn map_to_curve<H: Hash>(msg: &[u8], dst: &[u8]) -> Result<Self, InternalPakeError>;
/// Generates the contextString parameter as defined in
/// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-05.txt
@@ -34,12 +33,12 @@ pub trait GroupWithMapToCurve: Group {
}
impl GroupWithMapToCurve for RistrettoPoint {
const SUITE_ID: usize = 0x01;
const SUITE_ID: usize = 0x0001;
// Implements the hash_to_ristretto255() function from
// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-10.txt
fn map_to_curve(msg: &[u8], dst: &[u8]) -> Result<Self, InternalPakeError> {
let uniform_bytes = expand_message_xmd::<Sha256>(msg, dst, 64)?;
fn map_to_curve<H: Hash>(msg: &[u8], dst: &[u8]) -> Result<Self, InternalPakeError> {
let uniform_bytes = expand_message_xmd::<H>(msg, dst, 64)?;
Ok(<Self as Group>::hash_to_curve(
&GenericArray::clone_from_slice(&uniform_bytes[..]),
))
@@ -47,10 +46,12 @@ impl GroupWithMapToCurve for RistrettoPoint {
}
impl GroupWithMapToCurve for EdwardsPoint {
const SUITE_ID: usize = 0x09; // FIXME, seemingly unsupported by VOPRF RFC?
fn map_to_curve(msg: &[u8], dst: &[u8]) -> Result<Self, InternalPakeError> {
let (hashed_input, _) = Hkdf::<Sha256>::extract(Some(dst), msg);
Ok(<Self as Group>::hash_to_curve(&hashed_input))
const SUITE_ID: usize = 0x0009; // FIXME, seemingly unsupported by VOPRF RFC?
fn map_to_curve<H: Hash>(msg: &[u8], dst: &[u8]) -> Result<Self, InternalPakeError> {
let (hashed_input, _) = Hkdf::<H>::extract(Some(dst), msg);
Ok(<Self as Group>::hash_to_curve(
&GenericArray::clone_from_slice(&hashed_input[..]),
))
}
}
+2 -2
View File
@@ -137,7 +137,7 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
ClientRegistrationStartParameters::WithIdentifiers(id_u, id_s) => (id_u, id_s),
};
let (token, alpha) = oprf::blind::<R, CS::Group>(
let (token, alpha) = oprf::blind::<R, CS::Group, CS::Hash>(
&password,
blinding_factor_rng,
#[cfg(test)]
@@ -584,7 +584,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
}
};
let (token, alpha) = oprf::blind::<R, CS::Group>(
let (token, alpha) = oprf::blind::<R, CS::Group, CS::Hash>(
&password,
rng,
#[cfg(test)]
+12 -11
View File
@@ -17,21 +17,21 @@ pub struct Token<Grp: Group> {
pub(crate) blind: Grp::Scalar,
}
static STR_VOPRF: &[u8] = b"VOPRF05";
static STR_VOPRF_FINALIZE: &[u8] = b"VOPRF05-Finalize-";
static MODE_BASE: u8 = 0x01;
static STR_VOPRF: &[u8] = b"VOPRF06-HashToGroup-";
static STR_VOPRF_FINALIZE: &[u8] = b"VOPRF06-Finalize-";
static MODE_BASE: u8 = 0x00;
/// Computes the first step for the multiplicative blinding version of DH-OPRF. This
/// message is sent from the client (who holds the input) to the server (who holds the OPRF key).
/// The client can also pass in an optional "pepper" string to be mixed in with the input through
/// an HKDF computation.
pub(crate) fn blind<R: RngCore + CryptoRng, G: GroupWithMapToCurve>(
pub(crate) fn blind<R: RngCore + CryptoRng, G: GroupWithMapToCurve, H: Hash>(
input: &[u8],
blinding_factor_rng: &mut R,
#[cfg(test)] postprocess: fn(G::Scalar) -> G::Scalar,
) -> Result<(Token<G>, G), InternalPakeError> {
let dst = [STR_VOPRF, &G::get_context_string(MODE_BASE)].concat();
let mapped_point = G::map_to_curve(input, &dst)?;
let mapped_point = G::map_to_curve::<H>(input, &dst)?;
let blinding_factor = G::random_scalar(blinding_factor_rng);
#[cfg(test)]
let blind = postprocess(blinding_factor);
@@ -84,11 +84,11 @@ pub(crate) fn finalize<G: GroupWithMapToCurve, H: Hash>(
#[cfg(feature = "bench")]
#[doc(hidden)]
#[inline]
pub fn blind_shim<R: RngCore + CryptoRng, G: GroupWithMapToCurve>(
pub fn blind_shim<R: RngCore + CryptoRng, G: GroupWithMapToCurve, H: Hash>(
input: &[u8],
blinding_factor_rng: &mut R,
) -> Result<(Token<G>, G), InternalPakeError> {
blind(
blind::<R, G, H>(
input,
blinding_factor_rng,
#[cfg(test)]
@@ -129,13 +129,14 @@ mod tests {
use curve25519_dalek::ristretto::RistrettoPoint;
use generic_array::{arr, GenericArray};
use rand_core::OsRng;
use sha2::Sha256;
fn prf(
input: &[u8],
oprf_key: &[u8; 32],
) -> GenericArray<u8, <RistrettoPoint as Group>::ElemLen> {
let dst = [STR_VOPRF, &RistrettoPoint::get_context_string(MODE_BASE)].concat();
let point = RistrettoPoint::map_to_curve(input, &dst).unwrap();
let point = RistrettoPoint::map_to_curve::<Sha256>(input, &dst).unwrap();
let scalar =
RistrettoPoint::from_scalar_slice(GenericArray::from_slice(&oprf_key[..])).unwrap();
let res = point * scalar;
@@ -148,7 +149,7 @@ mod tests {
let input = b"hunter2";
let mut rng = OsRng;
let (token, alpha) =
blind::<_, RistrettoPoint>(&input[..], &mut rng, std::convert::identity)?;
blind::<_, RistrettoPoint, Sha256>(&input[..], &mut rng, std::convert::identity)?;
let oprf_key_bytes = arr![
u8; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32,
@@ -168,12 +169,12 @@ mod tests {
let mut input = vec![0u8; 64];
rng.fill_bytes(&mut input);
let (token, alpha) =
blind::<_, RistrettoPoint>(&input, &mut rng, std::convert::identity).unwrap();
blind::<_, RistrettoPoint, Sha256>(&input, &mut rng, std::convert::identity).unwrap();
let res =
finalize::<RistrettoPoint, sha2::Sha256>(&token.data, &unblind(&token, alpha), b"");
let dst = [STR_VOPRF, &RistrettoPoint::get_context_string(MODE_BASE)].concat();
let point = RistrettoPoint::map_to_curve(&input, &dst).unwrap();
let point = RistrettoPoint::map_to_curve::<Sha256>(&input, &dst).unwrap();
let res2 = finalize::<RistrettoPoint, sha2::Sha256>(&input, &point.to_arr().to_vec(), b"");
assert_eq!(res, res2);
+1
View File
@@ -5,3 +5,4 @@
pub mod mock_rng;
mod opaque_ke_test;
mod voprf_test_vectors;
+26 -26
View File
@@ -72,40 +72,40 @@ pub struct TestVectorParameters {
static TEST_VECTOR: &str = r#"
{
"client_s_pk": "9e1a7d68007f9db6f2cc515c9e42ce52eee78a6e4d6bca5a16d49bbfa4cd462e",
"client_s_sk": "101719337a212b3e55872a0c25874f420bb4510e445c527159ec3e23afe13c7c",
"client_e_pk": "5abe58c49c4fe4b3c82f6313857969cc9a2bc913865026ff39b0235636434844",
"client_e_sk": "78a41d08c2cb8e1dd3818a494136f5ee321ea2478ba161f0bcbc282c68467a5a",
"server_s_pk": "96118ab2892cb29ab29af9e8f0cf7d4d336e757e4f56bbe6afde887714118e12",
"server_s_sk": "70240d3fb3f49a289488f0b89b5f956276766efd5c1254317e72c4cb4d452840",
"server_e_pk": "9fe1377a64db22c3ae9ebe7d6016b5cbb8060448d8b5582548566f41202f7f33",
"server_e_sk": "2021fce09d946296e0a0671555d7552c7f1f69ed9d116cc3b6605449abcf6951",
"client_s_pk": "5320b55752ad2061c1804050f8a225a4ab1184bc17d8fa6b3c86470c33d9ce42",
"client_s_sk": "e8719d2f7aca0ab85a991ac4221ff7fde7665b9bd17658777c5417ef5c59796a",
"client_e_pk": "77fc3fefb8178ae08461756b54364c4f2d1363d5ce3187af128a3f84a6c5722a",
"client_e_sk": "48b452f6d0b28387cfa98245bda9230b6df215ed5b820bffb8511ec6802d8075",
"server_s_pk": "b8c5defc933aaf3640d13f217c392e06fe5fd41fae8571204fcbb804a566cd2e",
"server_s_sk": "60f5ab9ff1a3ba9cf6242812be91635db16e8e1826bf06fb97893d7cf82a2656",
"server_e_pk": "5a314dc389c12bf041b14e131fadebcc98e0fc33d3cd996ad9392c7ae6bff468",
"server_e_sk": "606034b9be54759ea5802a2dd71e4413e98d52c46e60f2d0868642ad9e6a9b46",
"id_u": "696455",
"id_s": "696453",
"password": "70617373776f7264",
"blinding_factor": "2d33e5917ed8ed3b4318dc15d6844fa7fae0b84210ac588350fccf2aa7e26b03",
"oprf_key": "90f32248c84a99c303dd97f5a6b80106a7324dd27cf1a9bdec725ce5be11f205",
"envelope_nonce": "491dc86966491b649bab099c1dd3a7927ea0ecb74b88d5d08c7267f151e9bf67",
"client_nonce": "741fbafaf51abbeab80434c1d1afccc81059b356b84ab704447d9632d5696d91",
"server_nonce": "745d196eac5679020332a2c237e63f56310741dbceb714cad4ea28680e5e52c9",
"blinding_factor": "c0accb2010d728cfce827d4cb3769000c8b42ac341db8ba196fbe75809d91300",
"oprf_key": "7f1d2a048a7aad9d1cf2b96473e3adbb1e0626eafe0abdfd09f1f700beda9d0f",
"envelope_nonce": "abb706633ac7092e2aa63dedd4b456d7d99870f099c4f2c51ba75da0f20db8e8",
"client_nonce": "1a92d39b2f9acdbef96dcc586b35ae056a085ede41b05f9f81801f69558d44c7",
"server_nonce": "e04e9f1a4d35882c0ce435e3f467f601f26fe246e5f60ee9b600d9a63b91c0ad",
"info1": "696e666f31",
"info2": "696e666f32",
"einfo2": "65696e666f32",
"info3": "696e666f33",
"einfo3": "65696e666f33",
"r1": "00204e61b9b1f2efbc4da7f114b9b8585ece25b3faec9c45e49ff60f310f61586417",
"r2": "0020fe43bff51e3868ecc913c97774e070e68acf5532f1862da20e554450f43856a2002096118ab2892cb29ab29af9e8f0cf7d4d336e757e4f56bbe6afde887714118e1201010103",
"r3": "491dc86966491b649bab099c1dd3a7927ea0ecb74b88d5d08c7267f151e9bf67002351e93c57b3c307d92ae0d38cbc9c66636511a3fa97bb34947e85c79dbafd670a22152a002303002096118ab2892cb29ab29af9e8f0cf7d4d336e757e4f56bbe6afde887714118e120020626884cb268cfbb7af1edd23ebe12c0cc995a95dffcf225ad9db330185846e9400209e1a7d68007f9db6f2cc515c9e42ce52eee78a6e4d6bca5a16d49bbfa4cd462e",
"l1": "00204e61b9b1f2efbc4da7f114b9b8585ece25b3faec9c45e49ff60f310f61586417741fbafaf51abbeab80434c1d1afccc81059b356b84ab704447d9632d5696d910005696e666f315abe58c49c4fe4b3c82f6313857969cc9a2bc913865026ff39b0235636434844",
"l2": "0020fe43bff51e3868ecc913c97774e070e68acf5532f1862da20e554450f43856a2491dc86966491b649bab099c1dd3a7927ea0ecb74b88d5d08c7267f151e9bf67002351e93c57b3c307d92ae0d38cbc9c66636511a3fa97bb34947e85c79dbafd670a22152a002303002096118ab2892cb29ab29af9e8f0cf7d4d336e757e4f56bbe6afde887714118e120020626884cb268cfbb7af1edd23ebe12c0cc995a95dffcf225ad9db330185846e942021fce09d946296e0a0671555d7552c7f1f69ed9d116cc3b6605449abcf69510005696e666f329fe1377a64db22c3ae9ebe7d6016b5cbb8060448d8b5582548566f41202f7f33000665696e666f32317af5691eb732163f54e2e497b5a883598baafce9a3a87a710f374b611aa3d5",
"l3": "0005696e666f33000665696e666f339ca8f1957db30ea986d9d29d9efc458476959dde2efeb4308bcde0e807152987",
"client_registration_state": "000369645500036964532d33e5917ed8ed3b4318dc15d6844fa7fae0b84210ac588350fccf2aa7e26b0370617373776f7264",
"client_login_state": "000369645500036964532d33e5917ed8ed3b4318dc15d6844fa7fae0b84210ac588350fccf2aa7e26b0378a41d08c2cb8e1dd3818a494136f5ee321ea2478ba161f0bcbc282c68467a5a741fbafaf51abbeab80434c1d1afccc81059b356b84ab704447d9632d5696d91c346939f310305b1a7e4a3d0958c3c8ecb62ba654f99a3f291aa17f665db721070617373776f7264",
"server_registration_state": "90f32248c84a99c303dd97f5a6b80106a7324dd27cf1a9bdec725ce5be11f205",
"server_login_state": "6b4d09544d05b91e31dca9fc27da533acd02bd7aafd10a715b479c7de2aedcdc5bf8effba8cc499e32894279cd7b70774a264c7813ad97e0360697b0a81ce1adcfa865f87aa285b8938e46b53f497852f2d88cf4c9302bd27debb02f582fb392",
"password_file": "90f32248c84a99c303dd97f5a6b80106a7324dd27cf1a9bdec725ce5be11f2059e1a7d68007f9db6f2cc515c9e42ce52eee78a6e4d6bca5a16d49bbfa4cd462e491dc86966491b649bab099c1dd3a7927ea0ecb74b88d5d08c7267f151e9bf67002351e93c57b3c307d92ae0d38cbc9c66636511a3fa97bb34947e85c79dbafd670a22152a002303002096118ab2892cb29ab29af9e8f0cf7d4d336e757e4f56bbe6afde887714118e120020626884cb268cfbb7af1edd23ebe12c0cc995a95dffcf225ad9db330185846e94",
"export_key": "a8a7ecd9f8e4fe53fd883655fb7eb1b52df11b5956b066dca30af60288520611",
"shared_secret": "cfa865f87aa285b8938e46b53f497852f2d88cf4c9302bd27debb02f582fb392"
"r1": "0020c4ad91692b704470e0613850b9bfcc5b265d43f9ba03dd6ff028f0fb6b365957",
"r2": "00205cbfd7b74c7fe6088f8117e7e63000675762920b75e0f4630ed67d4d960c7aa80020b8c5defc933aaf3640d13f217c392e06fe5fd41fae8571204fcbb804a566cd2e01010103",
"r3": "abb706633ac7092e2aa63dedd4b456d7d99870f099c4f2c51ba75da0f20db8e80023e76da9b9fbf400fea214ecdab24966e4d3fea9d0c3d5d672597e1e702eb30547495ada0023030020b8c5defc933aaf3640d13f217c392e06fe5fd41fae8571204fcbb804a566cd2e00204e0e5754fbbd48efcdab43cee37f6455f357f3edc54316cb69da8f8e92f5ed8900205320b55752ad2061c1804050f8a225a4ab1184bc17d8fa6b3c86470c33d9ce42",
"l1": "0020c4ad91692b704470e0613850b9bfcc5b265d43f9ba03dd6ff028f0fb6b3659571a92d39b2f9acdbef96dcc586b35ae056a085ede41b05f9f81801f69558d44c70005696e666f3177fc3fefb8178ae08461756b54364c4f2d1363d5ce3187af128a3f84a6c5722a",
"l2": "00205cbfd7b74c7fe6088f8117e7e63000675762920b75e0f4630ed67d4d960c7aa8abb706633ac7092e2aa63dedd4b456d7d99870f099c4f2c51ba75da0f20db8e80023e76da9b9fbf400fea214ecdab24966e4d3fea9d0c3d5d672597e1e702eb30547495ada0023030020b8c5defc933aaf3640d13f217c392e06fe5fd41fae8571204fcbb804a566cd2e00204e0e5754fbbd48efcdab43cee37f6455f357f3edc54316cb69da8f8e92f5ed89606034b9be54759ea5802a2dd71e4413e98d52c46e60f2d0868642ad9e6a9b460005696e666f325a314dc389c12bf041b14e131fadebcc98e0fc33d3cd996ad9392c7ae6bff468000665696e666f32661aa1d3e579032df30a78312d38a4c3d8d8a0f1b9bb7bbdbff040e0881a248e",
"l3": "0005696e666f33000665696e666f3317090781af5a220941ddd6db7d4f2af33d9b316a48aee163647131970bae50ba",
"client_registration_state": "00036964550003696453c0accb2010d728cfce827d4cb3769000c8b42ac341db8ba196fbe75809d9130070617373776f7264",
"client_login_state": "00036964550003696453c0accb2010d728cfce827d4cb3769000c8b42ac341db8ba196fbe75809d9130048b452f6d0b28387cfa98245bda9230b6df215ed5b820bffb8511ec6802d80751a92d39b2f9acdbef96dcc586b35ae056a085ede41b05f9f81801f69558d44c7288b735853d9e1d8ab699b7c4aef54680f036c56140dc0a4991f6d02a95babc970617373776f7264",
"server_registration_state": "7f1d2a048a7aad9d1cf2b96473e3adbb1e0626eafe0abdfd09f1f700beda9d0f",
"server_login_state": "2bfb97200c110fa3a9a020920829ce9e7e74a9e843ae86949e16300dc6e25b09e7e0522de623f021a7ba5d150ab8cba2eca4be458d3c22ae6109813a215a03d88f757f3390c767cd9433007c1abf9226c9e0da8e5d1a3d5722773c070b05f44b",
"password_file": "7f1d2a048a7aad9d1cf2b96473e3adbb1e0626eafe0abdfd09f1f700beda9d0f5320b55752ad2061c1804050f8a225a4ab1184bc17d8fa6b3c86470c33d9ce42abb706633ac7092e2aa63dedd4b456d7d99870f099c4f2c51ba75da0f20db8e80023e76da9b9fbf400fea214ecdab24966e4d3fea9d0c3d5d672597e1e702eb30547495ada0023030020b8c5defc933aaf3640d13f217c392e06fe5fd41fae8571204fcbb804a566cd2e00204e0e5754fbbd48efcdab43cee37f6455f357f3edc54316cb69da8f8e92f5ed89",
"export_key": "139998e9d44e2fa629689d8bef9f900a60278e2acd55f4e59906255b10494d58",
"shared_secret": "8f757f3390c767cd9433007c1abf9226c9e0da8e5d1a3d5722773c070b05f44b"
}
"#;
+182
View File
@@ -0,0 +1,182 @@
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
use crate::{errors::*, group::Group, oprf};
use curve25519_dalek::ristretto::RistrettoPoint;
use generic_array::GenericArray;
use rand_core::OsRng;
use serde_json::Value;
use sha2::Sha512;
struct VOPRFTestVectorParameters {
sksm: Vec<u8>,
input: Vec<u8>,
blind: Vec<u8>,
blinded_element: Vec<u8>,
evaluation_element: Vec<u8>,
unblinded_element: Vec<u8>,
info: Vec<u8>,
output: Vec<u8>,
}
// Taken from https://github.com/cfrg/draft-irtf-cfrg-voprf/blob/master/draft-irtf-cfrg-voprf.md
// in base mode
static OPRF_RISTRETTO255_SHA512: &'static [&str] = &[
r#"
{
"sksm": "c604c785ada70d77a5256ae21767de8c3304115237d262134f5e46e512cf8e03",
"input": "00",
"blind": "5ed895206bfc53316d307b23e46ecc6623afb3086da74189a416012be037e50b",
"blinded_element": "5cccd309ec729aebe398c53e19c0ab09c24a29f01036960bdad109852e7bdb44",
"evaluation_element": "86bd5eeabf29a87cb4a5c7207cb3ade5297e65f9b74c979bd3551891f4b21515",
"unblinded_element": "3c7f2d901c0d4f245503a186086fbdf5d8b4408432b25c5163e8b5a19c258348",
"info": "4f505246207465737420766563746f7273",
"output": "0bb570873cc0402ca38f1a2c395301f2a3627616e305f2bc54bb08c3f6ea9871eb71074e52e36b90778ba7c3e3429ef7170245c9e01647f3827fdef84d3ba930"
}
"#,
r#"
{
"sksm": "c604c785ada70d77a5256ae21767de8c3304115237d262134f5e46e512cf8e03",
"input": "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a",
"blind": "ed8366feb6b1d05d1f46acb727061e43aadfafe9c10e5a64e7518d63e3263503",
"blinded_element": "227d63ca69e93bd062193c1e97fff3d5ebf628f646009d77c4e22ba6429be154",
"evaluation_element": "063b91a12e7cbb98dfeb75d8a7eeb83aacf9fd6df7e0b4197466fb77a27fa631",
"unblinded_element": "804ec6774764ed50a0bbad0a5f477aa04df7323acab8f98ca6e468b7790bca4c",
"info": "4f505246207465737420766563746f7273",
"output": "af7cc264dbc96a6b898ba0fa33bfa9e1407bf1dcfbf8772204d470d4458b8f047806679dbfa251f656b906edf9fa638e268adf979bd0e2380a092047d61f9db9"
}
"#,
];
fn decode(values: &Value, key: &str) -> Option<Vec<u8>> {
values[key]
.as_str()
.and_then(|s| hex::decode(&s.to_string()).ok())
}
fn populate_test_vectors(values: &Value) -> VOPRFTestVectorParameters {
VOPRFTestVectorParameters {
sksm: decode(&values, "sksm").unwrap(),
input: decode(&values, "input").unwrap(),
blind: decode(&values, "blind").unwrap(),
blinded_element: decode(&values, "blinded_element").unwrap(),
evaluation_element: decode(&values, "evaluation_element").unwrap(),
unblinded_element: decode(&values, "unblinded_element").unwrap(),
info: decode(&values, "info").unwrap(),
output: decode(&values, "output").unwrap(),
}
}
// For fixing the blinding factor
fn postprocess_blinding_factor_oprf_ristretto255_sha512_0<G: Group>(_: G::Scalar) -> G::Scalar {
let parameters =
populate_test_vectors(&serde_json::from_str(OPRF_RISTRETTO255_SHA512[0]).unwrap());
G::from_scalar_slice(GenericArray::from_slice(&parameters.blind[..])).unwrap()
}
fn postprocess_blinding_factor_oprf_ristretto255_sha512_1<G: Group>(_: G::Scalar) -> G::Scalar {
let parameters =
populate_test_vectors(&serde_json::from_str(OPRF_RISTRETTO255_SHA512[1]).unwrap());
G::from_scalar_slice(GenericArray::from_slice(&parameters.blind[..])).unwrap()
}
// Tests input -> blind, blinded_element
#[test]
fn test_blind() -> Result<(), PakeError> {
for (i, tv) in OPRF_RISTRETTO255_SHA512.iter().enumerate() {
let parameters = populate_test_vectors(&serde_json::from_str(tv).unwrap());
let mut rng = OsRng;
let postprocess_fn: fn(
<RistrettoPoint as Group>::Scalar,
) -> <RistrettoPoint as Group>::Scalar = match i {
0 => postprocess_blinding_factor_oprf_ristretto255_sha512_0::<RistrettoPoint>,
1 => postprocess_blinding_factor_oprf_ristretto255_sha512_1::<RistrettoPoint>,
_ => panic!("Need to cover each test vector"),
};
let (token, blinded_element) = oprf::blind::<OsRng, RistrettoPoint, Sha512>(
&parameters.input,
&mut rng,
postprocess_fn,
)?;
assert_eq!(
&parameters.blind,
&RistrettoPoint::scalar_as_bytes(&token.blind).to_vec()
);
assert_eq!(
&parameters.blinded_element,
&blinded_element.to_arr().to_vec()
);
}
Ok(())
}
// Tests sksm, blinded_element -> evaluation_element
#[test]
fn test_evaluate() -> Result<(), PakeError> {
for tv in OPRF_RISTRETTO255_SHA512 {
let parameters = populate_test_vectors(&serde_json::from_str(tv).unwrap());
let evaluation_element = oprf::evaluate::<RistrettoPoint>(
RistrettoPoint::from_element_slice(GenericArray::from_slice(
&parameters.blinded_element,
))
.unwrap(),
&RistrettoPoint::from_scalar_slice(GenericArray::from_slice(&parameters.sksm)).unwrap(),
);
assert_eq!(
&parameters.evaluation_element,
&evaluation_element.to_arr().to_vec()
);
}
Ok(())
}
// Tests sksm, evaluation_element -> evaluation_element
#[test]
fn test_unblind() -> Result<(), PakeError> {
for tv in OPRF_RISTRETTO255_SHA512 {
let parameters = populate_test_vectors(&serde_json::from_str(tv).unwrap());
let token = oprf::Token {
data: parameters.input,
blind: RistrettoPoint::from_scalar_slice(GenericArray::from_slice(
&parameters.blind[..],
))
.unwrap(),
};
let unblinded_element = oprf::unblind::<RistrettoPoint>(
&token,
RistrettoPoint::from_element_slice(GenericArray::from_slice(
&parameters.evaluation_element,
))
.unwrap(),
);
assert_eq!(&parameters.unblinded_element, &unblinded_element);
}
Ok(())
}
// Tests input, unblinded_element, info -> output
#[test]
fn test_finalize() -> Result<(), PakeError> {
for tv in OPRF_RISTRETTO255_SHA512 {
let parameters = populate_test_vectors(&serde_json::from_str(tv).unwrap());
let output = oprf::finalize::<RistrettoPoint, Sha512>(
&parameters.input,
&parameters.unblinded_element,
&parameters.info,
);
assert_eq!(&parameters.output, &output.to_vec());
}
Ok(())
}