From 485d18deec18ff5d29405ccd190872581881f1ca Mon Sep 17 00:00:00 2001 From: Kevin Lewi Date: Mon, 13 Sep 2021 16:02:09 -0700 Subject: [PATCH] Matching to latest test vectors with metadata mode (#3) --- Cargo.toml | 2 + src/ciphersuite.rs | 22 +- src/errors.rs | 14 + src/group/mod.rs | 33 +- src/group/p256.rs | 9 +- src/group/ristretto.rs | 11 +- src/tests/mod.rs | 1 + src/tests/parser.rs | 109 +++++ src/tests/voprf_test_vectors.rs | 798 +++++++++++++++++++++++++++++--- src/voprf.rs | 459 +++++++++++++++--- 10 files changed, 1317 insertions(+), 141 deletions(-) create mode 100644 src/tests/parser.rs diff --git a/Cargo.toml b/Cargo.toml index a03c348..c37ce79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,9 +43,11 @@ bincode = "1" chacha20poly1305 = "0.8" criterion = "0.3" hex = "0.4" +json = "0.12" lazy_static = "1" serde_json = "1" sha2 = "0.9" proptest = "1" +regex = "1" rustyline = "8" voprf = { path = "", default-features = false, features = ["std"] } diff --git a/src/ciphersuite.rs b/src/ciphersuite.rs index c96e166..133e65d 100644 --- a/src/ciphersuite.rs +++ b/src/ciphersuite.rs @@ -5,7 +5,14 @@ //! Defines the CipherSuite trait to specify the underlying primitives for VOPRF -use crate::{group::Group, hash::Hash}; +use crate::{errors::InternalError, group::Group, hash::Hash}; + +static STR_VOPRF: &[u8] = b"VOPRF07-"; + +pub enum Mode { + Base = 0, + Verifiable = 1, +} /// Configures the underlying primitives used in VOPRF pub trait CipherSuite { @@ -14,4 +21,17 @@ pub trait CipherSuite { type Group: Group; /// The main hash function to use (for HKDF computations and hashing transcripts). type Hash: Hash; + + /// Generates the contextString parameter as defined in + /// + fn get_context_string(mode: Mode) -> Result, InternalError> { + use crate::serialization::i2osp; + + Ok([ + STR_VOPRF, + &i2osp(mode as usize, 1)?, + &i2osp(Self::Group::SUITE_ID, 2)?, + ] + .concat()) + } } diff --git a/src/errors.rs b/src/errors.rs index 36cfc27..506a6d8 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -30,6 +30,15 @@ pub enum InternalError { HashToCurveError, /// Failure to serialize or deserialize bytes SerializationError, + /// Use of incompatible modes (base vs. verifiable) + IncompatibleModeError, + /** + * Internal error thrown when different-lengthed slices are supplied + * to the compute_composites() function. + */ + MismatchedLengthsForCompositeInputs, + /// In verifiable mode, occurs when the proof failed to verify + ProofVerificationError, } impl Debug for InternalError { @@ -49,6 +58,11 @@ impl Debug for InternalError { Self::PointError => f.debug_tuple("PointError").finish(), Self::HashToCurveError => f.debug_tuple("HashToCurveError").finish(), Self::SerializationError => f.debug_tuple("SerializationError").finish(), + Self::IncompatibleModeError => f.debug_tuple("IncompatibleModeError").finish(), + Self::MismatchedLengthsForCompositeInputs => f + .debug_tuple("MismatchedLengthsForCompositeInputs") + .finish(), + Self::ProofVerificationError => f.debug_tuple("ProofVerificationError").finish(), } } } diff --git a/src/group/mod.rs b/src/group/mod.rs index d2c8d11..7257259 100644 --- a/src/group/mod.rs +++ b/src/group/mod.rs @@ -13,14 +13,19 @@ mod ristretto; use crate::errors::InternalError; use crate::hash::Hash; -use core::ops::Mul; +use core::ops::{Add, Mul, Sub}; use generic_array::{ArrayLength, GenericArray}; use rand::{CryptoRng, RngCore}; use zeroize::Zeroize; /// A prime-order subgroup of a base field (EC, prime-order field ...). This /// subgroup is noted additively — as in the draft RFC — in this trait. -pub trait Group: Copy + Sized + for<'a> Mul<&'a ::Scalar, Output = Self> { +pub trait Group: + Copy + + Sized + + for<'a> Mul<&'a ::Scalar, Output = Self> + + for<'a> Add<&'a Self, Output = Self> +{ /// The ciphersuite identifier as dictated by /// const SUITE_ID: usize; @@ -31,16 +36,12 @@ pub trait Group: Copy + Sized + for<'a> Mul<&'a ::Scalar, Output /// Hashes a slice of pseudo-random bytes to a scalar fn hash_to_scalar(input: &[u8], dst: &[u8]) -> Result; - /// Generates the contextString parameter as defined in - /// - fn get_context_string(mode: u8) -> Result, InternalError> { - use crate::serialization::i2osp; - - Ok([i2osp(mode as usize, 1)?, i2osp(Self::SUITE_ID, 2)?].concat()) - } - /// The type of base field scalars - type Scalar: Zeroize + Copy; + type Scalar: Zeroize + + Copy + + for<'a> Add<&'a Self::Scalar, Output = Self::Scalar> + + for<'a> Sub<&'a Self::Scalar, Output = Self::Scalar> + + for<'a> Mul<&'a Self::Scalar, Output = Self::Scalar>; /// The byte length necessary to represent scalars type ScalarLen: ArrayLength + 'static; /// Return a scalar from its fixed-length bytes representation @@ -70,8 +71,16 @@ pub trait Group: Copy + Sized + for<'a> Mul<&'a ::Scalar, Output fn mult_by_slice(&self, scalar: &GenericArray) -> Self; /// Returns if the group element is equal to the identity (1) - fn is_identity(&self) -> bool; + fn is_identity(&self) -> bool { + self.ct_equal(&::identity()) + } + + /// Returns the identity group element + fn identity() -> Self; /// Compares in constant time if the group elements are equal fn ct_equal(&self, other: &Self) -> bool; + + /// Compares in constant time if the scalars are equal + fn ct_equal_scalar(s1: &Self::Scalar, s2: &Self::Scalar) -> bool; } diff --git a/src/group/p256.rs b/src/group/p256.rs index 4269264..5eba0fc 100644 --- a/src/group/p256.rs +++ b/src/group/p256.rs @@ -149,12 +149,17 @@ impl Group for ProjectivePoint { self * &Self::Scalar::from_bytes_reduced(scalar) } - fn is_identity(&self) -> bool { - self == &Self::identity() + fn identity() -> Self { + Self::identity() } + fn ct_equal(&self, other: &Self) -> bool { self.ct_eq(other).into() } + + fn ct_equal_scalar(s1: &Self::Scalar, s2: &Self::Scalar) -> bool { + s1.ct_eq(s2).into() + } } /// Corresponds to the map_to_curve_simple_swu() function defined in diff --git a/src/group/ristretto.rs b/src/group/ristretto.rs index 61149cf..2985689 100644 --- a/src/group/ristretto.rs +++ b/src/group/ristretto.rs @@ -78,9 +78,11 @@ impl Group for RistrettoPoint { } } } + fn scalar_as_bytes(scalar: Self::Scalar) -> GenericArray { scalar.to_bytes().into() } + fn scalar_invert(scalar: &Self::Scalar) -> Self::Scalar { scalar.invert() } @@ -107,12 +109,15 @@ impl Group for RistrettoPoint { self * Scalar::from_bits(*scalar.as_ref()) } - /// Returns if the group element is equal to the identity (1) - fn is_identity(&self) -> bool { - self == &Self::identity() + fn identity() -> Self { + ::identity() } fn ct_equal(&self, other: &Self) -> bool { ConstantTimeEq::ct_eq(self, other).into() } + + fn ct_equal_scalar(s1: &Self::Scalar, s2: &Self::Scalar) -> bool { + ConstantTimeEq::ct_eq(s1, s2).into() + } } diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 461d37b..8a8e91b 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -4,4 +4,5 @@ // LICENSE file in the root directory of this source tree. mod mock_rng; +mod parser; mod voprf_test_vectors; diff --git a/src/tests/parser.rs b/src/tests/parser.rs new file mode 100644 index 0000000..afd6fc0 --- /dev/null +++ b/src/tests/parser.rs @@ -0,0 +1,109 @@ +// 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 alloc::string::String; + +pub(crate) fn rfc_to_json(input: &str) -> String { + format!("{{\n{}\n}}", parse_ciphersuites(input)) +} + +fn parse_ciphersuites(input: &str) -> String { + let re = regex::Regex::new(r"## OPRF\((?P.+?)\)").unwrap(); + let mut ciphersuites = vec![]; + + let chunks: Vec<&str> = re.split(input).collect(); + let mut count = 1; + for caps in re.captures_iter(input) { + let ciphersuite = format!( + "\"{}\": {{ {} }}", + caps["ciphersuite"].to_string(), + parse_modes(chunks[count]) + ); + ciphersuites.push(ciphersuite); + count += 1; + } + + ciphersuites.join(",\n") +} + +fn parse_modes(input: &str) -> String { + let re = regex::Regex::new(r"### (?P.*+) Mode").unwrap(); + let mut modes = vec![]; + + let chunks: Vec<&str> = re.split(input).collect(); + let mut count = 1; + for caps in re.captures_iter(input) { + let mode = format!( + "\"{}\": [\n {} \n]", + caps["mode"].to_string(), + parse_vectors(chunks[count]) + ); + modes.push(mode); + count += 1; + } + + modes.join(",\n") +} + +fn parse_vectors(input: &str) -> String { + let re = regex::Regex::new(r"Test Vector.*+\n").unwrap(); + let mut vectors = vec![]; + + let chunks: Vec<&str> = re.split(input).collect(); + let init_params = parse_params(chunks[0]); + + let mut count = 1; + for _ in re.captures_iter(input) { + let params = format!("{{\n{},\n{}\n}}", init_params, parse_params(chunks[count])); + vectors.push(params); + count += 1; + } + + vectors.join(",\n") +} + +fn parse_params(input: &str) -> String { + let mut params = vec![]; + let mut param = String::new(); + + let mut lines = input.lines(); + + loop { + match lines.next() { + None => { + // Clear out any existing string and flush to params + param += "\""; + params.push(param); + + return params.join(",\n"); + } + Some(line) => { + // If line contains =, then + if line.contains('=') { + // Clear out any existing string and flush to params + if param.len() > 0 { + param += "\""; + params.push(param); + } + + let mut iter = line.split('='); + let key = iter.next().unwrap().split_whitespace().next().unwrap(); + let val = iter.next().unwrap().split_whitespace().next().unwrap(); + + param = format!(" \"{}\": \"{}", key, val); + } else { + let s = line.trim().to_string(); + if s.contains("~") || s.contains("#") { + // Ignore comment lines + continue; + } + if s.len() > 0 { + param += &s; + } + } + } + } + } +} diff --git a/src/tests/voprf_test_vectors.rs b/src/tests/voprf_test_vectors.rs index 87b63c0..124fb9f 100644 --- a/src/tests/voprf_test_vectors.rs +++ b/src/tests/voprf_test_vectors.rs @@ -6,48 +6,29 @@ use crate::ciphersuite::CipherSuite; use crate::errors::*; use crate::group::Group; -use crate::tests::mock_rng::CycleRng; -use crate::voprf::{Client, Server}; +use crate::tests::{mock_rng::CycleRng, parser::*}; +use crate::voprf::{NonVerifiableClient, NonVerifiableServer}; use alloc::string::ToString; use alloc::vec::Vec; use curve25519_dalek::ristretto::RistrettoPoint; use generic_array::GenericArray; -use serde_json::Value; +use json::JsonValue; use sha2::Sha512; +#[derive(Debug)] struct VOPRFTestVectorParameters { + seed: Vec, sksm: Vec, - input: Vec, - blind: Vec, - blinded_element: Vec, - evaluation_element: Vec, - output: Vec, + input: Vec>, + info: Vec, + blind: Vec>, + blinded_element: Vec>, + evaluation_element: Vec>, + output: Vec>, } // Taken from https://github.com/cfrg/draft-irtf-cfrg-voprf/blob/master/draft-irtf-cfrg-voprf.md // in base mode -static OPRF_RISTRETTO255_SHA512: &[&str] = &[ - r#" - { - "sksm": "caeff69352df4905a9121a4997704ca8cee1524a110819eb87deba1a39ec1701", - "input": "00", - "blind": "c604c785ada70d77a5256ae21767de8c3304115237d262134f5e46e512cf8e03", - "blinded_element": "fc20e03aff3a9de9b37e8d35886ade11ec7d85c2a1fb5bb0b1686c64e07ac467", - "evaluation_element": "7c72cc293cd7d44c0b57c273f27befd598b132edc665694bdc9c42a4d3083c0a", - "output": "e3a209dce2d3ea3d84fcddb282818caebb756a341e08a310d9904314f5392085d13c3f76339d745db0f46974a6049c3ea9546305af55d37760b2136d9b3f0134" - } - "#, - r#" - { - "sksm": "caeff69352df4905a9121a4997704ca8cee1524a110819eb87deba1a39ec1701", - "input": "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a", - "blind": "5ed895206bfc53316d307b23e46ecc6623afb3086da74189a416012be037e50b", - "blinded_element": "483d4f39de5ff77fa0f9a0ad2334dd5bf87f2cda868539d21de67ce49e7d1536", - "evaluation_element": "026f2758fc62f02a7ff95f35ec6f20186aa57c0274361655543ea235d7b2aa34", - "output": "2c17dc3e9398dadb44bb2d3360c446302e99f1fe0ec40f0b1ad25c9cf002be1e4b41b4900ef056537fe8c14532ccea4d796f5feab9541af48057d83c0db86fe9" - } - "#, -]; #[cfg(feature = "p256")] static OPRF_P256_SHA256: &[&str] = &[ r#" @@ -72,20 +53,685 @@ static OPRF_P256_SHA256: &[&str] = &[ "#, ]; -fn decode(values: &Value, key: &str) -> Option> { +static OPRF_TEST_VECTORS: &str = r#" +## OPRF(ristretto255, SHA-512) + +### Base Mode + +~~~ +seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a +3a3 +skSm = caeff69352df4905a9121a4997704ca8cee1524a110819eb87deba1a39ec1 +701 +~~~ + +#### Test Vector 1, Batch Size 1 + +~~~ +Input = 00 +Info = 7465737420696e666f +Blind = c604c785ada70d77a5256ae21767de8c3304115237d262134f5e46e512cf +8e03 +BlindedElement = fc20e03aff3a9de9b37e8d35886ade11ec7d85c2a1fb5bb0b16 +86c64e07ac467 +EvaluationElement = 922e4c04b9f3b3e795d322a306c0ab9d96b667df9b949c05 +2c8c75435a9dbf2f +Output = 9e857d0e8523b8eb9e995d455ae6ae19f75d85ac8b5df62c50616fb5aa0 +ced3da5646698089c36dead28f9ad8e489fc0ee1c8e168725c38ed50f3783a5c520c +e +~~~ + +#### Test Vector 2, Batch Size 1 + +~~~ +Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a +Info = 7465737420696e666f +Blind = 5ed895206bfc53316d307b23e46ecc6623afb3086da74189a416012be037 +e50b +BlindedElement = 483d4f39de5ff77fa0f9a0ad2334dd5bf87f2cda868539d21de +67ce49e7d1536 +EvaluationElement = 6eef6ee53c6fb17c77ae47e78bdca2e1094f98785e7b9a14 +f09be20797dad656 +Output = b090b2ff80028771c14fecf2f37c1b14e46deec59c83d3b943c51d315bd +3bf7d32c399ed0c4ce6003339ab9ed4ad168bfb595e43530c9d73ff02ab0f1263d93 +b +~~~ + +### Verifiable Mode + +~~~ +seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a +3a3 +skSm = ac37d5850510299406ea8eb8fa226a7bfc2467a4b070d6c7bf667948b9600 +b00 +pkSm = 0c0254e22063cae3e1bae02fb6fa20882664a117c0278eda6bda3372c0dd9 +860 +~~~ + +#### Test Vector 1, Batch Size 1 + +~~~ +Input = 00 +Info = 7465737420696e666f +Blind = ed8366feb6b1d05d1f46acb727061e43aadfafe9c10e5a64e7518d63e326 +3503 +BlindedElement = 3a0a53f2c57e5ee0d89e394087f8e5f95b24159db01c31933a0 +7f0e6414c954d +EvaluationElement = f8a50ed35a477b0cde91d926e1bc5ae59b97d5bd0dda51a7 +28b0f036ec557d79 +EvaluationProofC = 7a5375eb1dbad259431f5c294e816a1c1483c279748da1a75 +d91f8a81438ea08 +EvaluationProofS = 355d4087d4d848b46878dcc8fb5849ac7a09133382c2c6129 +564a7f7b4b7bf01 +Output = 4b2ff4c984985829c3cd9d90c255cdc0d6b61c4c0aafa9215769d51cf7d +eb01472ba945928a8305e010f12b7dcc75a9dc2460439e6297d57dc2ce7ca0abaae1 +a +~~~ + +#### Test Vector 2, Batch Size 1 + +~~~ +Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a +Info = 7465737420696e666f +Blind = e6d0f1d89ad552e383d6c6f4e8598cc3037d6e274d22da3089e7afbd4171 +ea02 +BlindedElement = a86dd4544d0f3ea973926054230767dff16016215f2d73f26d3 +f86a81f38cf1a +EvaluationElement = 9e47810f1de1b57ebe163a95c170ec165a2063f872155c37 +6d94e8de2157af70 +EvaluationProofC = 61075125d851d5164b0aa1a4d5ddeebaf097266450ac60195 +79af5f7abd19008 +EvaluationProofS = 8eb0f6f1e7f9d8bfddbc21ae3c25a065e6c4e797d15f345ed +4fb9ee468d24c0a +Output = fe1fb7fa49c37dc7cd31d64859b4a2e6ae0cef294f2764e6f12f7d809f2 +18047d1fde147cf69807b8971fb2c316eb572be2b5bf491813bfec0a20668d6d07b0 +b +~~~ + +#### Test Vector 3, Batch Size 2 + +~~~ +Input = 00,5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a +Info = 7465737420696e666f +Blind = 80513e77795feeec6d2c450589b0e1b178febd5c193a9fcba0d27f0a06e0 +d50f,533c2e6d91c934f919ac218973be55ba0d7b234160a0d4cf3bddafbda99e2e0 +c +BlindedElement = c24645d6378a4a86ec4682a8d86f368b1e7db870fd709a45102 +492bcdc17e904,0e5ec78f839a8b6e86999bc180602690a4daae57bf5d7f827f3d40 +2f56cc6c51 +EvaluationElement = 3afe48eab00493eb1b073e95f57a456cde9aefe463dd1e6d +0144bf6e99ce411c,daaf9421318fd2c7fcdf369cb348748cf4dd177cce30ee4d13c +eb1644b85b653 +EvaluationProofC = 601381ecbe127ada04c057b8b1fc21d912f71e49252780dd0 +d0ac768b233ce03 +EvaluationProofS = 5f9b489a994c1d14b92d603ebcffee4f5cfadc953f69bb626 +48c6e662613ae00 +Output = 4b2ff4c984985829c3cd9d90c255cdc0d6b61c4c0aafa9215769d51cf7d +eb01472ba945928a8305e010f12b7dcc75a9dc2460439e6297d57dc2ce7ca0abaae1 +a,fe1fb7fa49c37dc7cd31d64859b4a2e6ae0cef294f2764e6f12f7d809f218047d1 +fde147cf69807b8971fb2c316eb572be2b5bf491813bfec0a20668d6d07b0b +~~~ + +## OPRF(decaf448, SHAKE-256) + +### Base Mode + +~~~ +seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a +3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3 +skSm = 78f2622804104209f7e015370ff98f4a3cbf311e6784e9f4944f8a252dc08 +e916d9ab1a60dc905f0e56631903ecd4ae6e15291776d61460b +~~~ + +#### Test Vector 1, Batch Size 1 + +~~~ +Input = 00 +Info = 7465737420696e666f +Blind = d1080372f0fcf8c5eace50914e7127f576725f215cc7c111673c635ce668 +bbbb9b50601ad89b358ab8c23ed0b6c9d040365ec9d060868714 +BlindedElement = 984e0a443ee194090737df4afb402253f216b77650c91d252b6 +638e1179723d51a4154b88eae396f1320f5df3c4b17f779516c456e364bd1 +EvaluationElement = de477252a5ff3c7d51ce159cb8ccf1865d8c7d3402824163 +8d80971f13a59d87b2b1036341b98089555ab088278391794c49bbb052fdbcff +Output = df8f910c3b84d1f3ca6afd1992768608a20f2ad7b770e9d89d303c88ba1 +5bb7d991f2f7ffd5b5b51fa3bcf8fa06779609497f6c0ae4e9cb2dcd48c68b4ac6b9 +4 +~~~ + +#### Test Vector 2, Batch Size 1 + +~~~ +Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a +Info = 7465737420696e666f +Blind = aed1ffa44fd8f0ed16373606a3cf7df589cca86d8ea1abbf5768771dbef3 +d401c74ae55ba1e28b9565e1e4018eb261a14134a4ce60c1c718 +BlindedElement = 4aa751f84b2634b73efa364b03e60b92b84f457576e6b369eea +b76140e3859d10d2e98174f13f5a2c70670529ccf093d5f1aaf355b4f830b +EvaluationElement = 085ea1cb452a2fb15b3a0d0e1c86899c7ea49fe2e4856ef4 +f95bc2542eec610fc09b0fe7d7ed7389d86af6a646695b7ad46527dc2a936aa4 +Output = b57516a737879ece1110ad5d051ac0a6c54e1dcd989c907721ecebab5b4 +5877cc693c3c05d0bd416c5a9ceba36de41a0a31679c146fe4c110c64b056eba1720 +b +~~~ + +### Verifiable Mode + +~~~ +seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a +3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3 +skSm = 9eb722f7fee9f61f24ad31bc42309f73648cf4393929e8f5f333fe10c6975 +c827a1eba4e03ae2fa8735db2f63f6c98c7af6010e64c81f535 +pkSm = b6e2751176d57836fe1dfbdbbdc78a1b5c5a52f831226c9d8dfdf5daf8f46 +6e310e80978e9b81c387f5bc85cc7ef5567f4dd3ba7674579a2 +~~~ + +#### Test Vector 1, Batch Size 1 + +~~~ +Input = 00 +Info = 7465737420696e666f +Blind = 4c936db1779a621b6c71475ac3111fd5703a59b713929f36dfd1e892a7fe +814479c93d8b4b6e11d1f6fe5351e51457b665fa7b76074e531f +BlindedElement = d0b8e2eecad2816d45c1f8a072fe6db77d18f4b26f0889c98e2 +ef856ac5df82090c1fbeac9c8e732f192b66c3b4c3f1e446ab8910c86be2f +EvaluationElement = d29849d8ad1e651328e8119003debd9ecd54cc786a5eb8ae +ea56487ffc09120e98792f9475605488d16623b8e3cfa5af1ec27e76bc841b75 +EvaluationProofC = 8b3b8f0c9eb22527e419f5a03d4d3f34cf725837424a38c5b +4f88c7759f7a54bade57b7930bfeff051be9bfeaabc8976ed407398e0ce462a +EvaluationProofS = 062e068a8d57bc1c411bc42fe714626cfb92ad854a56636c2 +b83f2b5215c2ff531b22e4d37031523db203556959e275b46b84303ed23fc37 +Output = 1ff5c5c2c081c76006b52c45f79728882dc48962036ea7d4d5097b04e93 +9ae81118a7fe5f0a66a6131bef18b9cd998150f10c62619ec4c2d223ea57dc67f153 +d +~~~ + +#### Test Vector 2, Batch Size 1 + +~~~ +Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a +Info = 7465737420696e666f +Blind = 15b3355179392f40c3d5a15f0d5ffc354e340454ec779f575e4573a3886a +b5e57e4da2985cea9e32f6d95539ce2c7189e1bd7462e8c5483a +BlindedElement = 0e7ddd85c8bc5382e908241c6151afe23a41e0396759b5e38a9 +affd996cd822bca242a499793555fc15f07bffdaaa93b42568b307fbdca0f +EvaluationElement = 4c81e29e8a9502fa02e00cb09cf40d9b98988ac9b4bce7cc +a0656caeb0926b59c7000d7fe6c5dd814f831864547d2360d223a50077bd04fe +EvaluationProofC = 74fc8fbf2e669dc5d25898ea8ce45d1d3eb97edb4b7c3cee3 +9865a3c66da6b7bad4ad3e77794d6f5e82fa8a645b9b973a8612bfcd1194302 +EvaluationProofS = f700ee3433e876d83f96bb70f19ff292605ad4c9466fd71db +c2ed22ade0130574e5ee343ef45d42e834a11a19fd6f5b1b5ef910bcccf731b +Output = 2753e222528f1ee5fcc6ad4bf1ca953e5d3b47c1dfae85710f46a0a030c +07f59055e9b05dacb729a7ce41cd2ed782f8a76a1b3f74b40196aed0b6938b89c60f +9 +~~~ + +#### Test Vector 3, Batch Size 2 + +~~~ +Input = 00,5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a +Info = 7465737420696e666f +Blind = 614bb578f29cc677ea9e7aea3e4839413997e020f9377b63c13584156a09 +a46dd2a425c41eac0e313a47e99d05df72c6e1d58e6592577a0d,4c115060bca87db +7d73e00cbb8559f84cb7a221b235b0950a0ab553f03f10e1386abe954011b7da62bb +6599418ef90b5d4ea98cc28aff517 +BlindedElement = 5e481a4d7eaa5bab831f53f9a6311851dafd4318c6462eed4f6 +15004afdb082da2f99670b0963985faac21c30eea19aacfc441412edb4c0b,8e043b +9b7afeafa07e39d9b8b88957ff07d69124b1a2b841e18c9ffb52ebf0c25144eb2501 +a1d7983a44604f33a36e925eebc9bec65d9c54 +EvaluationElement = 8a0d34fdb0b55121421546ff952c7bd3cbe469926ff9ad4f +aeba243823955529eeae4f1a7a64cd055ec01baa041a99dfbe1a67ca4d59f93d,5e8 +6e0b41cc88186ee0003baa46535e71acd98453b298976b92be2cca2646e88620f55d +f6bf4754456dfd8d84f6889c17b5ff93052325a1a +EvaluationProofC = 1ff624a102b99771c76a9414e9b3f33127897d971bc84a922 +e464805e4a9f27b889922030adebbbd58e0ab618ade9c84bfe8aa226176f11f +EvaluationProofS = 432958ea1e6f69263aef51db9efb23ee504d233c17e9077c0 +373401da167637a1df4eafd9c2537c9f89c103f9e635931fe2042419dd9bd37 +Output = 1ff5c5c2c081c76006b52c45f79728882dc48962036ea7d4d5097b04e93 +9ae81118a7fe5f0a66a6131bef18b9cd998150f10c62619ec4c2d223ea57dc67f153 +d,2753e222528f1ee5fcc6ad4bf1ca953e5d3b47c1dfae85710f46a0a030c07f5905 +5e9b05dacb729a7ce41cd2ed782f8a76a1b3f74b40196aed0b6938b89c60f9 +~~~ + +## OPRF(P-256, SHA-256) + +### Base Mode + +~~~ +seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a +3a3 +skSm = a1b2355828f2c76de6749af9d093bd9fe0f2cada3ec653cd9a6d3126a7a78 +27b +~~~ + +#### Test Vector 1, Batch Size 1 + +~~~ +Input = 00 +Info = 7465737420696e666f +Blind = 5d9e7f6efd3093c32ecceabd57fb03cf760c926d2a7bfa265babf29ec98a +f0d0 +BlindedElement = 03e3c379698da853d9844098fa0ac676970d5ec24167b598714 +cd2ee188604ddd2 +EvaluationElement = 030d8d882120e8fa67ef978a9abac506acd5ec731b8e8d6f +15035e29241dd2ced2 +Output = ab653a4f3b357177b125e1c6d0bd2c0bc409b7ed5f48c99537fbd7fd11e +f8133 +~~~ + +#### Test Vector 2, Batch Size 1 + +~~~ +Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a +Info = 7465737420696e666f +Blind = 825155ab61f17605af2ae2e935c78d857c9407bcd45128d57d338f1671b5 +fcbe +BlindedElement = 030b40be181ffbb3c3ae4a4911287c43261f5e4034781def69c +51608f372a02102 +EvaluationElement = 03991df04e3e526d457065b6eafc855aa2fc4528c22d2b51 +6a3c71227b1b488f44 +Output = eca4df985f7c49b091c3ce4217be1f26cdc6a148b681ed1f1638d09dfd2 +13e6e +~~~ + +### Verifiable Mode + +~~~ +seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a +3a3 +skSm = 4e7804245a743c59d624457677294e04a8bc4bdcd94f0d3bd54f568067489 +d34 +pkSm = 03b51a0af95c819b09ee80c2056cf0ab0551a5355266d3a0aaff90c3fe915 +ed892 +~~~ + +#### Test Vector 1, Batch Size 1 + +~~~ +Input = 00 +Info = 7465737420696e666f +Blind = cee64d86fd20ab4caa264a26c0e3d42fb773b3173ba76f9588c9b14779bd +8d91 +BlindedElement = 0222f5dba2da1ec7bd1086d0e04894ef1da1c11163daf376b2b +c76cc51edb16815 +EvaluationElement = 02f2767135f75f69b257675b38f2bcd50338a655a5092166 +3c8942ca61ea7d3c29 +EvaluationProofC = ffa082fc9f9a287e7edc50e3ad879ee13aebd24b69124792b +df047c643f70af2 +EvaluationProofS = b50907b2fa188b90aff3b25e1d9abb02e9e2c8bfdc525c61c +a008428940fca64 +Output = c74d46cc93e578f7048bc6b852cd9bc1d9ebb90c586308f9202b9deedc8 +94448 +~~~ + +#### Test Vector 2, Batch Size 1 + +~~~ +Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a +Info = 7465737420696e666f +Blind = 5c4b401063eff0bf242b4cd534a79bacfc2e715b2db1e7a3ad4ff8af1b24 +daa2 +BlindedElement = 02f84403d1ceb40a3668349f7c349f806d2c858785853324c66 +7505018d13ee160 +EvaluationElement = 0216d7d342ef50113244b444dfedaec78810959e40fef0a6 +922658d44accb1e9c1 +EvaluationProofC = f496e58818c25ffb386f22ceb57a83da1200612b67aaa0760 +8b3375c25b297e0 +EvaluationProofS = 3e67d1f6094a8012725dc63a0c2f4f870173b97a3daa03588 +f777655a087fbbf +Output = 90a9f5ff4208a5505d1b7ed65eb233bb61b4c999ffa0d8cd1d98fb717b9 +2fe28 +~~~ + +#### Test Vector 3, Batch Size 2 + +~~~ +Input = 00,5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a +Info = 7465737420696e666f +Blind = f0c7822ba317fb5e86028c44b92bd3aedcf6744d388ca013ef33edd36930 +4eda,3b9631be9f8b274d9aaf671bfb6a775229bf435021b89c683259773bc686956 +b +BlindedElement = 02a840214a74345570dcadfc927e726901b257b447234fac509 +0a1830295ca736c,039a5a8152abb0154b4d79a90486e358ea325980f0bf590524c4 +460f700454238f +EvaluationElement = 025991aac0b0c79bb1185c0b1e64964656634dfcd755cdf5 +da9ee52be0b5d5f742,03319e3baba8fa7f60dab49ef0ba68b7a85bccb5d4968643e +2f029b6c0826911d1 +EvaluationProofC = 51b5ed453168480a2e95863cda1f4d28ad5bc91e8c9c75d78 +8569aea1679794a +EvaluationProofS = 642087db120a2b3ce839f57041801f37cd4a6c05b69b327b8 +77810293f7b09a8 +Output = c74d46cc93e578f7048bc6b852cd9bc1d9ebb90c586308f9202b9deedc8 +94448,90a9f5ff4208a5505d1b7ed65eb233bb61b4c999ffa0d8cd1d98fb717b92fe +28 +~~~ + +## OPRF(P-384, SHA-512) + +### Base Mode + +~~~ +seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a +3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3 +skSm = ef1b52c12cdf43dc260bf5425a30cde7d708ec34b38dcfbdc2946d7baf525 +361e797f6a98f1ebd80f64865f21cde1c6d +~~~ + +#### Test Vector 1, Batch Size 1 + +~~~ +Input = 00 +Info = 7465737420696e666f +Blind = 359073c015b92d15450f7fb395bf52c6ea98384c491fe4e4d423b59de7b0 +df382902c13bdc9993d3717bda68fc080b99 +BlindedElement = 02fa3115c21ffcacc09ca470729b725781f84333e217cfeec2b +8ba6a54ce492ede7ead3714c5b177427ef853effb1b5c24 +EvaluationElement = 033a4bdea2693686e4ce467c8a5cdfc41b86ad20aaaa9bc1 +6e75b59dbd41dab0bc9af0041e551ece3b4c9fb2315d8d1fa9 +Output = a5a0ef3fb964a36097662d1258ef0f93b224ddd81a356c37d5dd05a885a +0b6722b90c1f5181637fece7ed180ba053da23bf35cef7a87dcba75562cb7a264001 +8 +~~~ + +#### Test Vector 2, Batch Size 1 + +~~~ +Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a +Info = 7465737420696e666f +Blind = 21ece4f9b6ffd01ce82082545413bd9bb5e8f3c63b86ae88d9ce0530b01c +b1c23382c7ec9bdd6e75898e4877d8e2bc17 +BlindedElement = 025fddc89a832089a59120df742acb34dba82b26afcae977961 +57df238b5905c494a23c56b1f485cbbff78d31df7fa1492 +EvaluationElement = 02f8b59813663e7965c219c113c560482cbea7ca4c412a0c +f3fd855ee7d543ae926d29ace85296f195f988be284b2347f6 +Output = f2a0b355cae4ae2c717d0b48e39c0ee356db3ca446fddf85cddb74f397e +b85046da62d0d85d55d19d39dd9b68fcc39379ec6d3b93ba33909fcc96361d225cdd +e +~~~ + +### Verifiable Mode + +~~~ +seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a +3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3 +skSm = 67ee1c9e67566d87bfcca9e5dac4bfdb8bdd727c031133fac2aa9ba6c41e6 +1e5f8fd401b5d76c7d54b15b15932797479 +pkSm = 029b51b2ce9c499f2056e65e0f41d60960f9c4795c0cf94af273ce840c20b +e4cdf87690b6b121b37d399b49afcc2ec9ac3 +~~~ + +#### Test Vector 1, Batch Size 1 + +~~~ +Input = 00 +Info = 7465737420696e666f +Blind = 102f6338df84c9602bfa9e7d690b1f7a173d07e6d54a419db4a6308f8b09 +589e4283efb9cd1ee4061c6bf884e60a8774 +BlindedElement = 02a1f41323e91a6ac9fbbb5b8e4c7c58a4c5bcbaa4195557182 +cd59e826dc847f1e077de1d402ac92eafe322461fc0d582 +EvaluationElement = 03af3164f8721a57931f92884b43c58ff0ed1be249f7e1c9 +3033a5909f0ffc59ed3fea9452ec5c9cfb865b8bd2e65cd209 +EvaluationProofC = 44108ca9b342f4d7e31a250aa9f41afb0de840e113dbb6bb8 +2b5e6735aef18a20867a63628be6e109d2d687e1faa8888 +EvaluationProofS = 270f1173bc6f916e21142096d23d17194edf844074922c287 +a50182f87bbb5fc3a966c8851dd6799ec5cfe59c7063c7f +Output = 065094c66d66b6541aa1e09d99e2fdaac727356e9cd1c18275b7127be51 +eb1ce7f37ad5924f7425d60828c2d1acc69bef40d11423bba8f9e34478e04c437fbe +0 +~~~ + +#### Test Vector 2, Batch Size 1 + +~~~ +Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a +Info = 7465737420696e666f +Blind = 8aec1d0c3d16afd032da7ba961449a56cec6fb918e932b06d5778ac7f67b +ecfb3e3869237f74106241777f230582e84a +BlindedElement = 02b3465d70f76de3eaf6ecb8080490288f741c622c06d023bd1 +80a55a2e3e4eaad08533651f9d278a3f59cec8277780303 +EvaluationElement = 03a53e01901893585437cd48a1eea1188fc8e9275a80cf43 +370a451c476dae3b84ca8c7bf44fcac2fa3eeab933b25da0c3 +EvaluationProofC = 5ebc467e78ae29f7d741221df0ee67285df72ec482fdc8e5b +de7e588b12fcba86f4f116c23ee6b32c0f38f2daac67e86 +EvaluationProofS = 9e53e7e0494cc883e4984daf10a55819bbb5ce7e9005f143b +3dda88d8a35649269a4658a98c81c814097d15a3dcf4dbe +Output = 5f557169680da50500b5333a26bb2ba79256c0ecc351051d32cac540920 +267a40b246deb286c9ecb0025dede808465f85d6a5e75aca61088533b306d8646c92 +c +~~~ + +#### Test Vector 3, Batch Size 2 + +~~~ +Input = 00,5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a +Info = 7465737420696e666f +Blind = 41fabd4722d92472d858051ce9ad1a533176a862c697b2c392aff2aeb77e +b20c2ae6ba52fe31e13e03bf1d9f39878b23,51171628f1d28bb7402ca4aea6465e2 +67b7f977a1fb71593281099ef2625644aee0b6c5f5e6e01a2b052b3bd4caf539b +BlindedElement = 02d715dfce1a0724071fa8e530d79f7b234a31739a64166e0fe +21fa6fa0fe19e1ab5e468becca899f31e365c47f3efb2ef,028dfd0c7a38b4cb8477 +cae34f041344fb44fc9e55bfa3cf55ab7b4764b74accc7b49c0ff09a524598033dad +1152fb3a1c +EvaluationElement = 03f9a8c81c108201888eb86348c6f80691d99425272972b5 +bf41d3038af0eeb04d60edd9ea288625a7166a8c17cea0083f,02abb31980533dbf7 +eb5fee0a8969089b3e16585a2cd41a34067592a2021b1b4ea3d1cef3e7c87a6f284c +0e45546c92d98 +EvaluationProofC = f0f7bd2723c3460d5c5ab03092c6861fb34253470ef430dac +9aeac6ce48984b28d91178061cba02e3e911c4aa97229d5 +EvaluationProofS = 19755db385ddd08064fdf8405897d1dea472688934088505e +89dcff91081fec1d2e37c1d4c5a9dddbdd358aa89f63b46 +Output = 065094c66d66b6541aa1e09d99e2fdaac727356e9cd1c18275b7127be51 +eb1ce7f37ad5924f7425d60828c2d1acc69bef40d11423bba8f9e34478e04c437fbe +0,5f557169680da50500b5333a26bb2ba79256c0ecc351051d32cac540920267a40b +246deb286c9ecb0025dede808465f85d6a5e75aca61088533b306d8646c92c +~~~ + +## OPRF(P-521, SHA-512) + +### Base Mode + +~~~ +seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a +3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a +3a3 +skSm = 016ee706f30ce7e15e4ffa3114c7d59a7b6f302d531ca60419be39d1cd43e +e13b1fc8398b7f63a900cdc49c6e99f65a74403db2fa739927a2ee288cff857d9d84 +ecf +~~~ + +#### Test Vector 1, Batch Size 1 + +~~~ +Input = 00 +Info = 7465737420696e666f +Blind = 01b983705fcc9a39607288b935b0797ac6b3c4b2e848823ac9ae16b3a3b5 +816be03432370deb7c3c17d9fc7cb4e0ce646e04e42d638e0fa7a434ed340772a8b5 +d626 +BlindedElement = 0301f0a8c68e58f5571bd39fe3b0b2aa055a8c34e3d68ba0d2e +d177db0bc7575d477ed8f557596feb5ac568fe738eee8cff7dcb56dc78f52bf381c0 +912e0e84b5a3f5b +EvaluationElement = 0200d7b1131aa9f8c365de7bd7903738f61bdecfaada375a +ba3905bdaad1301c7cd537f69abff04140ccca29a4c46cb4a036160e55a9621210b3 +71d84646b0199571fa +Output = 61eea8fedfa9338dd22fac279f1f3f9e96693919c59ea3918c7a441115e +6bdecb1d05b5da55d4024858c92d3911a81d4eca362123b2911e5dc58591bf7be29c +7 +~~~ + +#### Test Vector 2, Batch Size 1 + +~~~ +Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a +Info = 7465737420696e666f +Blind = 01a03b1096b0316bc8567c89bd70267d35c8ddcb2be2cdc867089a2eb5cf +471b1e6eb4b043b9644c8539857abe3a2022e9c9fd6a1695bbabe8add48bcd149ff3 +b841 +BlindedElement = 030099c35342a43221c6e03debfb17bad71b62e04c9242aa6e9 +f2f915163ef4f5b8b7fe1740a4d636c36bd5c73ca39c69992dc7f6dff8f232125efc +22af4df8352fea2 +EvaluationElement = 0300ceeba6751486eecc479ab2259e3a57c13b0710f61c82 +87acad60624974b76ea242dbcae3a9daad1bdc9c49012c8d8b384d510980cc1ef8fa +8d10502748ce63d93f +Output = 6682273a5199b2454a706cac557008e2264580ac39b6995e1f47130b985 +d1015de7713d3bdb121212a68de2ece73bf72e41738a01c23428753c44e3dd39b5de +3 +~~~ + +### Verifiable Mode + +~~~ +seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a +3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a +3a3 +skSm = 0017674057e06c5e3e8a331f2dc3558540701c9cd0f4c19126d5972af6a01 +447b312d05a06dab3e9e07c891d749444c27ede0897ad42aea03b887eb5db93e3f29 +a86 +pkSm = 0201ee4e2eaa74728f577f4bb282c5440cd454fdee1d79b15a36d34b5e5a1 +25e3ccc0f99e32cc0a6a15b5652a0c8a424860c6753f685d0e1e150ceba24ca3386f +29216 +~~~ + +#### Test Vector 1, Batch Size 1 + +~~~ +Input = 00 +Info = 7465737420696e666f +Blind = 00bbb82117c88bbd91b8954e16c0b9ceed3ce992b198be1ebfba9ba970db +d75beefbfc6d056b7f7ba1ef79f4facbf2d912c26ce2ecc5bb8d66419b379952e96b +d6f5 +BlindedElement = 0200357f949a0a0bdfeb682734dbdeb778f3845045617b21436 +27753332e2e75458ab183b12635c75e19afaf56981e7755803026842db1b22fa42c8 +61413d07ff86545 +EvaluationElement = 0201d636bac3f77c1091b337daae32259a3eacd57e3c0fb1 +444fe5ce22af6acdcef4a46a2b5e169aa8d0e26ec2a3621c15dd366ba1978dae761c +1ef3dac63c60cbee88 +EvaluationProofC = 011ebe27ebc79e5679b643c6b3a51333499c7abee86c09218 +1c0a8e7e539e0ba30b1c128666708c753696ace2aa789c4975b0b80d6241a1dafe85 +c39a7338d1e20d0 +EvaluationProofS = 0131c8a81b5f64209f8fe53e8c6a00789a893f20596198e25 +21275e05d92529808e9f54030fc8be2ce78c6df0d29e6fd7d8e623e0ccc7b19b1944 +93dacd2a4eb3a32 +Output = c51295e2a03ba59f1538734316e0d70dd81f95daba2f7b5ac4906c56ce8 +79d6cef8f583433c981a182a52dd568811b073f65fc1124941f344cc9dd3b3880f29 +5 +~~~ + +#### Test Vector 2, Batch Size 1 + +~~~ +Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a +Info = 7465737420696e666f +Blind = 009055c99bf9591cb0eab2a72d044c05ca2cc2ef9b609a38546f74b6d688 +f70cf205f782fa11a0d61b2f5a8a2a1143368327f3077c68a1545e9aafbba6a90dc0 +d40a +BlindedElement = 030185e431f056e75ba7fac49da70790031daa333d16f05e1de +471e24afe0ed985c770ce77bd1bebec527e9a76feecc6afd92c5fd00481ba7fb843d +2aab52337cb716e +EvaluationElement = 02000859e1abc2ed28086b854ec5ae72311244fdeedf81d7 +69af6a6f2c83f00fa48df1f1a0c0b6fac84cc654b7757ac042107a6b3043e483bb3b +74de5d6c301b20e8f6 +EvaluationProofC = 01629dd5af14c7414801d879b1018ce06bcc5c5d0a64ca422 +b76aaa531c8ecca630919fb4b51fa60fdc215f73e67e8d617d55ca6a227343d434d5 +e0f487567f85bfa +EvaluationProofS = 016959443267bb7d9a5c5e5b1c4d20026394b4edaca7dfbc1 +aa3b3c2020cf99579cf276c0e84f0cb5a820226fa3b81d42de2db39d8412642e7042 +8e485a61ee9d760 +Output = 7462f460340a52f7b7609c5e1c5e2d5334d43da7631cb549bb65163a05d +1b2e936669e52e66c92da4b2e24fff3c118c62787577c01d2885567b476c13011057 +1 +~~~ + +#### Test Vector 3, Batch Size 2 + +~~~ +Input = 00,5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a +Info = 7465737420696e666f +Blind = 01c6cf092d80c7cf2cb55388d899515238094c800bdd9c65f71780ba85f5 +ae9b4703e17e559ca3ccd1944f9a70536c175f11a827452672b60d4e9f89eba28104 +6e29,00cba1ba1a337759061965a423d9d3d6e1e1006dc8984ad28a4c93ecfc36fc2 +171046b3c4284855cfa2434ed98db9e68a597db2c14728fade716a6a82d600444b26 +e +BlindedElement = 0301978860af75cd69acbc93e8c9fc530e5d2b2208da42c65bf +e079f0f6e0b3fc6080556c10739271d2a8fe578409d4fa9b19ef0484d9c15451c4e7 +0501e31da7608cb,0200e30565c3d7e02c822762f25db4c872811adb2cbfbad92b04 +291bc8c476d0546d1c5ecf5c58ff06b8d19aad8eca9e5f1a80ff8e981ebc490b0cfb +d5d499b47bad8e +EvaluationElement = 0300abdee910f144c3be460e724c11626e1f9986f72e2c43 +3a9c4dad2ef6fcb9249c9a5036334ba88b0892462b6f8ad419c38cc259b0c774a9bd +0c4d545d0914413ea2,02019696f91dcc178bbe6b97f822cdc4052f9b94852ff6023 +f6068848f867df40e54a5f1525e7fafa383e82fe36bf3c74427b51903032d0f89876 +05bf24ee003f37693 +EvaluationProofC = 008fa896b69c1efc4e9c6bdfd0b149444532d5ba3bfd957cf +7cd71c374d3a1cca25f17b60616164377b0734243bc878e17d3ecab36b3e3565b5c6 +218dae92d40c0be +EvaluationProofS = 018707381f6f4b0153044737030b5d9851c15609532da8932 +c1fa1f4901dba05a4118d25142344f9ea1465c907eb13d908a45d8b98265eac48819 +a04cae859b0643a +Output = c51295e2a03ba59f1538734316e0d70dd81f95daba2f7b5ac4906c56ce8 +79d6cef8f583433c981a182a52dd568811b073f65fc1124941f344cc9dd3b3880f29 +5,7462f460340a52f7b7609c5e1c5e2d5334d43da7631cb549bb65163a05d1b2e936 +669e52e66c92da4b2e24fff3c118c62787577c01d2885567b476c130110571 +~~~ +"#; + +macro_rules! parse { + ( $v:ident, $s:expr ) => { + parse_default!($v, $s, vec![]) + }; +} + +macro_rules! parse_default { + ( $v:ident, $s:expr, $d:expr ) => { + match decode(&$v, $s) { + Some(x) => x, + None => $d, + } + }; +} + +macro_rules! json_to_test_vectors { + ( $v:ident, $cs:expr, $mode:expr ) => { + $v[$cs][$mode] + .members() + .map(|x| populate_test_vectors(&x)) + .collect::>() + }; +} + +#[test] +fn test_print_json() -> () { + let json = rfc_to_json(OPRF_TEST_VECTORS); + println!("{}", &json); +} + +fn decode(values: &JsonValue, key: &str) -> Option> { values[key] .as_str() .and_then(|s| hex::decode(&s.to_string()).ok()) } -fn populate_test_vectors(values: &Value) -> VOPRFTestVectorParameters { +fn decode_vec(values: &JsonValue, key: &str) -> Option>> { + let s = values[key].as_str().unwrap(); + match s.contains(',') { + true => Some( + s.split(',') + .map(|x| hex::decode(&x.to_string()).unwrap()) + .collect(), + ), + false => Some(vec![hex::decode(&s.to_string()).unwrap()]), + } +} + +fn populate_test_vectors(values: &JsonValue) -> 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(), - output: decode(&values, "output").unwrap(), + seed: decode(&values, "seed").unwrap(), + sksm: decode(&values, "skSm").unwrap(), + input: decode_vec(&values, "Input").unwrap(), + info: parse!(values, "Info"), + blind: decode_vec(&values, "Blind").unwrap(), + blinded_element: decode_vec(&values, "BlindedElement").unwrap(), + evaluation_element: decode_vec(&values, "EvaluationElement").unwrap(), + output: decode_vec(&values, "Output").unwrap(), } } @@ -97,9 +743,17 @@ fn tests() -> Result<(), InternalError> { type Hash = Sha512; } - test_blind::(OPRF_RISTRETTO255_SHA512)?; - test_evaluate::(OPRF_RISTRETTO255_SHA512)?; - test_finalize::(OPRF_RISTRETTO255_SHA512)?; + let rfc = json::parse(rfc_to_json(OPRF_TEST_VECTORS).as_str()).expect("Could not parse json"); + + let ristretto_base_tvs = json_to_test_vectors!( + rfc, + String::from("ristretto255, SHA-512"), + String::from("Base") + ); + + test_blind::(&ristretto_base_tvs)?; + test_evaluate::(&ristretto_base_tvs)?; + test_finalize::(&ristretto_base_tvs)?; #[cfg(feature = "p256")] { @@ -109,28 +763,30 @@ fn tests() -> Result<(), InternalError> { type Hash = sha2::Sha256; } - test_blind::(OPRF_P256_SHA256)?; - test_evaluate::(OPRF_P256_SHA256)?; - test_finalize::(OPRF_P256_SHA256)?; + let p256_base_tvs = + json_to_test_vectors!(rfc, String::from("P-256, SHA-256"), String::from("Base")); + + test_blind::(&p256_base_tvs)?; + test_evaluate::(&p256_base_tvs)?; + test_finalize::(&p256_base_tvs)?; } Ok(()) } // Tests input -> blind, blinded_element -fn test_blind(tvs: &[&str]) -> Result<(), InternalError> { - for tv in tvs { - let parameters = populate_test_vectors(&serde_json::from_str(tv).unwrap()); - - let mut rng = CycleRng::new(parameters.blind.to_vec()); - let (client, blinded_element) = Client::::blind(¶meters.input, &mut rng)?; +fn test_blind(tvs: &[VOPRFTestVectorParameters]) -> Result<(), InternalError> { + for parameters in tvs { + let mut rng = CycleRng::new(parameters.blind[0].to_vec()); + let (client, blinded_element) = + NonVerifiableClient::::blind(¶meters.input[0], &mut rng)?; assert_eq!( - ¶meters.blind, + ¶meters.blind[0], &CS::Group::scalar_as_bytes(client.get_blind()).to_vec() ); assert_eq!( - ¶meters.blinded_element, + ¶meters.blinded_element[0], &blinded_element.to_arr().to_vec() ); } @@ -138,18 +794,17 @@ fn test_blind(tvs: &[&str]) -> Result<(), InternalError> { } // Tests sksm, blinded_element -> evaluation_element -fn test_evaluate(tvs: &[&str]) -> Result<(), InternalError> { - for tv in tvs { - let parameters = populate_test_vectors(&serde_json::from_str(tv).unwrap()); - - let server = Server::::new_with_key(¶meters.sksm).unwrap(); +fn test_evaluate(tvs: &[VOPRFTestVectorParameters]) -> Result<(), InternalError> { + for parameters in tvs { + let server = NonVerifiableServer::::new_with_key(¶meters.sksm).unwrap(); let evaluation_element = server.evaluate( - CS::Group::from_element_slice(GenericArray::from_slice(¶meters.blinded_element)) + CS::Group::from_element_slice(GenericArray::from_slice(¶meters.blinded_element[0])) .unwrap(), - ); + ¶meters.info, + )?; assert_eq!( - ¶meters.evaluation_element, + ¶meters.evaluation_element[0], &evaluation_element.to_arr().to_vec() ); } @@ -157,23 +812,24 @@ fn test_evaluate(tvs: &[&str]) -> Result<(), InternalError> { } // Tests input, blind, evaluation_element -> output -fn test_finalize(tvs: &[&str]) -> Result<(), InternalError> { - for tv in tvs { - let parameters = populate_test_vectors(&serde_json::from_str(tv).unwrap()); - - let client = Client::::from_data_and_blind( - ¶meters.input, +fn test_finalize(tvs: &[VOPRFTestVectorParameters]) -> Result<(), InternalError> { + for parameters in tvs { + let client = NonVerifiableClient::::from_data_and_blind( + ¶meters.input[0], &::from_scalar_slice(&GenericArray::clone_from_slice( - ¶meters.blind, + ¶meters.blind[0], )) .unwrap(), ); - let output = client.finalize(::from_element_slice( - GenericArray::from_slice(¶meters.evaluation_element), - )?)?; + let output = client.finalize( + ::from_element_slice(GenericArray::from_slice( + ¶meters.evaluation_element[0], + ))?, + ¶meters.info, + )?; - assert_eq!(¶meters.output, &output.to_vec()); + assert_eq!(¶meters.output[0], &output.to_vec()); } Ok(()) } diff --git a/src/voprf.rs b/src/voprf.rs index 440b5e6..67d377e 100644 --- a/src/voprf.rs +++ b/src/voprf.rs @@ -3,11 +3,12 @@ // This source code is licensed under the MIT license found in the // LICENSE file in the root directory of this source tree. -use crate::ciphersuite::CipherSuite; -use crate::errors::InternalError; -use crate::group::Group; -use crate::hash::Hash; -use crate::serialization::serialize; +use crate::{ + ciphersuite::{CipherSuite, Mode}, + errors::InternalError, + group::Group, + serialization::{i2osp, serialize}, +}; use digest::Digest; use generic_array::GenericArray; use rand::{CryptoRng, RngCore}; @@ -15,36 +16,32 @@ use rand::{CryptoRng, RngCore}; use alloc::vec; use generic_array::typenum::Unsigned; -static STR_VOPRF: &[u8] = b"HashToGroup-VOPRF07-"; -static STR_VOPRF_FINALIZE: &[u8] = b"Finalize-VOPRF07-"; -static MODE_BASE: u8 = 0x00; +static STR_HASH_TO_SCALAR: &[u8] = b"HashToScalar-"; +static STR_HASH_TO_GROUP: &[u8] = b"HashToGroup-"; +static STR_FINALIZE: &[u8] = b"Finalize-"; +static STR_SEED: &[u8] = b"Seed-"; +static STR_CONTEXT: &[u8] = b"Context-"; +static STR_COMPOSITE: &[u8] = b"Composite-"; +static STR_CHALLENGE: &[u8] = b"Challenge-"; -pub struct Client { +pub struct NonVerifiableClient { data: alloc::vec::Vec, blind: ::Scalar, } -impl Client { +impl NonVerifiableClient { /// Computes the first step for the multiplicative blinding version of DH-OPRF. pub fn blind( input: &[u8], blinding_factor_rng: &mut R, ) -> Result<(Self, CS::Group), InternalError> { - // Choose a random scalar that must be non-zero - let blind = ::random_nonzero_scalar(blinding_factor_rng); - let dst = [ - STR_VOPRF, - &::get_context_string(MODE_BASE)?, - ] - .concat(); - let mapped_point = ::map_to_curve::(input, &dst)?; - let blind_token = mapped_point * &blind; + let (blind, blinded_element) = blind::(input, blinding_factor_rng)?; Ok(( Self { data: input.to_vec(), blind, }, - blind_token, + blinded_element, )) } @@ -53,10 +50,11 @@ impl Client { pub fn finalize( &self, evaluated_element: CS::Group, + info: &[u8], ) -> Result::OutputSize>, InternalError> { let unblinded_element = evaluated_element * &::scalar_invert(&self.blind); - finalize_after_unblind::(&self.data, unblinded_element) + finalize_after_unblind::(&self.data, unblinded_element, info, Mode::Base) } #[cfg(test)] @@ -75,42 +73,371 @@ impl Client { } } -pub struct Server { - oprf_key: ::Scalar, +pub struct VerifiableClient { + data: alloc::vec::Vec, + blind: ::Scalar, + blinded_element: CS::Group, } -impl Server { +impl VerifiableClient { + /// Computes the first step for the multiplicative blinding version of DH-OPRF. + pub fn blind( + input: &[u8], + blinding_factor_rng: &mut R, + ) -> Result<(Self, CS::Group), InternalError> { + let (blind, blinded_element) = blind::(input, blinding_factor_rng)?; + Ok(( + Self { + data: input.to_vec(), + blind, + blinded_element, + }, + blinded_element, + )) + } + + /// Computes the third step for the multiplicative blinding version of DH-OPRF, in which + /// the client unblinds the server's message. + pub fn finalize( + &self, + evaluated_element: CS::Group, + proof: Proof, + pk: CS::Group, + info: &[u8], + ) -> Result::OutputSize>, InternalError> { + let unblinded_element = verifiable_unblind( + self.blind, + evaluated_element, + self.blinded_element, + pk, + proof, + info, + )?; + finalize_after_unblind::(&self.data, unblinded_element, info, Mode::Verifiable) + } + + #[cfg(test)] + /// Only used for test functions + pub fn from_data_and_blind( + data: &[u8], + blind: &::Scalar, + blinded_element: &CS::Group, + ) -> Self { + Self { + data: data.to_vec(), + blind: blind.clone(), + blinded_element: blinded_element.clone(), + } + } + + #[cfg(test)] + /// Only used for test functions + pub fn get_blind(&self) -> ::Scalar { + self.blind + } +} + +fn verifiable_unblind( + blind: ::Scalar, + evaluated_element: CS::Group, + blinded_element: CS::Group, + pk: CS::Group, + proof: Proof, + info: &[u8], +) -> Result { + let context = [ + STR_CONTEXT, + &CS::get_context_string(Mode::Verifiable)?, + &serialize(info, 2)?, + ] + .concat(); + + let dst = [ + STR_HASH_TO_SCALAR, + &CS::get_context_string(Mode::Verifiable)?, + ] + .concat(); + let m = CS::Group::hash_to_scalar::(&context, &dst)?; + + let g = CS::Group::base_point(); + let t = g * &m; + let u = t + &pk; + + verify_proof(g, u, evaluated_element, blinded_element, proof)?; + + let unblinded_element = evaluated_element * &CS::Group::scalar_invert(&blind); + Ok(unblinded_element) +} + +pub struct NonVerifiableServer { + sk: ::Scalar, +} + +impl NonVerifiableServer { pub fn new(rng: &mut R) -> Result { - let mut key = vec![0u8; ::OutputSize::USIZE]; - rng.fill_bytes(&mut key); - Self::new_with_key(&key) + let mut seed = vec![0u8; ::OutputSize::USIZE]; + rng.fill_bytes(&mut seed); + Self::new_from_seed(&seed) } pub fn new_with_key(key: &[u8]) -> Result { - Ok(Self { - oprf_key: CS::Group::from_scalar_slice(&GenericArray::clone_from_slice(key))?, - }) + let sk = CS::Group::from_scalar_slice(&GenericArray::clone_from_slice(key))?; + Ok(Self { sk }) + } + + // Corresponds to DeriveKeyPair from the VOPRF spec + pub fn new_from_seed(seed: &[u8]) -> Result { + let dst = [STR_HASH_TO_SCALAR, &CS::get_context_string(Mode::Base)?].concat(); + let sk = CS::Group::hash_to_scalar::(seed, &dst)?; + Ok(Self { sk }) } /// Computes the second step for the multiplicative blinding version of DH-OPRF. This /// message is sent from the server (who holds the OPRF key) to the client. - pub fn evaluate(&self, point: CS::Group) -> CS::Group { - point * &self.oprf_key + pub fn evaluate( + &self, + blinded_element: CS::Group, + info: &[u8], + ) -> Result { + let context = [ + STR_CONTEXT, + &CS::get_context_string(Mode::Base)?, + &serialize(info, 2)?, + ] + .concat(); + let dst = [STR_HASH_TO_SCALAR, &CS::get_context_string(Mode::Base)?].concat(); + let m = CS::Group::hash_to_scalar::(&context, &dst)?; + let t = self.sk + &m; + let evaluated_element = blinded_element * &CS::Group::scalar_invert(&t); + Ok(evaluated_element) } } -fn finalize_after_unblind( +pub struct VerifiableServer { + sk: ::Scalar, + pk: CS::Group, +} + +impl VerifiableServer { + pub fn new(rng: &mut R) -> Result { + let mut seed = vec![0u8; ::OutputSize::USIZE]; + rng.fill_bytes(&mut seed); + Self::new_from_seed(&seed) + } + + pub fn new_with_key(key: &[u8]) -> Result { + let sk = CS::Group::from_scalar_slice(&GenericArray::clone_from_slice(key))?; + let pk = CS::Group::base_point() * &sk; + Ok(Self { sk, pk }) + } + + // Corresponds to DeriveKeyPair from the VOPRF spec + pub fn new_from_seed(seed: &[u8]) -> Result { + let dst = [ + STR_HASH_TO_SCALAR, + &CS::get_context_string(Mode::Verifiable)?, + ] + .concat(); + let sk = CS::Group::hash_to_scalar::(seed, &dst)?; + let pk = CS::Group::base_point() * &sk; + Ok(Self { sk, pk }) + } + + /// Computes the second step for the multiplicative blinding version of DH-OPRF. This + /// message is sent from the server (who holds the OPRF key) to the client. + pub fn evaluate( + &self, + rng: &mut R, + blinded_element: CS::Group, + info: &[u8], + ) -> Result<(CS::Group, Proof), InternalError> { + let context = [ + STR_CONTEXT, + &CS::get_context_string(Mode::Base)?, + &serialize(info, 2)?, + ] + .concat(); + let dst = [STR_HASH_TO_SCALAR, &CS::get_context_string(Mode::Base)?].concat(); + let m = CS::Group::hash_to_scalar::(&context, &dst)?; + let t = self.sk + &m; + let evaluated_element = blinded_element * &CS::Group::scalar_invert(&t); + + let g = CS::Group::base_point(); + let u = g * &t; + + let proof = generate_proof(rng, t, g, u, evaluated_element, blinded_element)?; + + Ok((evaluated_element, proof)) + } + + pub fn get_public_key(&self) -> CS::Group { + self.pk + } +} + +// Inner function for blind. Returns the blind scalar and the blinded element +fn blind( input: &[u8], - unblinded_element: G, -) -> Result::OutputSize>, InternalError> { - let finalize_dst = [STR_VOPRF_FINALIZE, &G::get_context_string(MODE_BASE)?].concat(); + blinding_factor_rng: &mut R, +) -> Result<(::Scalar, CS::Group), InternalError> { + // Choose a random scalar that must be non-zero + let blind = ::random_nonzero_scalar(blinding_factor_rng); + let dst = [STR_HASH_TO_GROUP, &CS::get_context_string(Mode::Base)?].concat(); + let mapped_point = ::map_to_curve::(input, &dst)?; + let blinded_element = mapped_point * &blind; + Ok((blind, blinded_element)) +} + +#[allow(clippy::many_single_char_names)] +fn generate_proof( + rng: &mut R, + k: ::Scalar, + a: CS::Group, + b: CS::Group, + c: CS::Group, + d: CS::Group, +) -> Result, InternalError> { + let (m, z) = compute_composites::(Some(k), b, &[c], &[d])?; + + let r = CS::Group::random_nonzero_scalar(rng); + let t2 = a * &r; + let t3 = m * &r; + + let challenge_dst = [STR_CHALLENGE, &CS::get_context_string(Mode::Verifiable)?].concat(); + let h2_input = [ + serialize(&b.to_arr().to_vec(), 2)?, + serialize(&m.to_arr().to_vec(), 2)?, + serialize(&z.to_arr().to_vec(), 2)?, + serialize(&t2.to_arr().to_vec(), 2)?, + serialize(&t3.to_arr().to_vec(), 2)?, + serialize(&challenge_dst, 2)?, + ] + .concat(); + + let hash_to_scalar_dst = [ + STR_HASH_TO_SCALAR, + &CS::get_context_string(Mode::Verifiable)?, + ] + .concat(); + let c = CS::Group::hash_to_scalar::(&h2_input, &hash_to_scalar_dst)?; + + let s = r - &(c * &k); + + Ok(Proof { + c_scalar: c, + s_scalar: s, + }) +} + +pub struct Proof { + c_scalar: ::Scalar, + s_scalar: ::Scalar, +} + +#[allow(clippy::many_single_char_names)] +fn verify_proof( + a: CS::Group, + b: CS::Group, + c: CS::Group, + d: CS::Group, + proof: Proof, +) -> Result<(), InternalError> { + let (m, z) = compute_composites::(None, b, &[c], &[d])?; + let t2 = (a * &proof.s_scalar) + &(b * &proof.c_scalar); + let t3 = (m * &proof.s_scalar) + &(z * &proof.c_scalar); + + let challenge_dst = [STR_CHALLENGE, &CS::get_context_string(Mode::Verifiable)?].concat(); + let h2_input = [ + serialize(&b.to_arr().to_vec(), 2)?, + serialize(&m.to_arr().to_vec(), 2)?, + serialize(&z.to_arr().to_vec(), 2)?, + serialize(&t2.to_arr().to_vec(), 2)?, + serialize(&t3.to_arr().to_vec(), 2)?, + serialize(&challenge_dst, 2)?, + ] + .concat(); + + let hash_to_scalar_dst = [ + STR_HASH_TO_SCALAR, + &CS::get_context_string(Mode::Verifiable)?, + ] + .concat(); + let c = CS::Group::hash_to_scalar::(&h2_input, &hash_to_scalar_dst)?; + + match CS::Group::ct_equal_scalar(&c, &proof.c_scalar) { + true => Ok(()), + false => Err(InternalError::ProofVerificationError), + } +} + +fn finalize_after_unblind( + input: &[u8], + unblinded_element: CS::Group, + info: &[u8], + mode: Mode, +) -> Result::OutputSize>, InternalError> { + let finalize_dst = [STR_FINALIZE, &CS::get_context_string(mode)?].concat(); let hash_input = [ serialize(input, 2)?, + serialize(info, 2)?, serialize(&unblinded_element.to_arr().to_vec(), 2)?, serialize(&finalize_dst, 2)?, ] .concat(); - Ok(::digest(&hash_input)) + Ok(::digest(&hash_input)) +} + +fn compute_composites( + k_option: Option<::Scalar>, + b: CS::Group, + c_slice: &[CS::Group], + d_slice: &[CS::Group], +) -> Result<(CS::Group, CS::Group), InternalError> { + if c_slice.len() != d_slice.len() { + return Err(InternalError::MismatchedLengthsForCompositeInputs); + } + + let seed_dst = [STR_SEED, &CS::get_context_string(Mode::Verifiable)?].concat(); + let composite_dst = [STR_COMPOSITE, &CS::get_context_string(Mode::Verifiable)?].concat(); + + let h1_input = [ + serialize(&b.to_arr().to_vec(), 2)?, + serialize(&seed_dst, 2)?, + ] + .concat(); + let seed = ::digest(&h1_input); + + let mut m = CS::Group::identity(); + let mut z = CS::Group::identity(); + + for i in 0..c_slice.len() { + let h2_input = [ + serialize(&seed, 2)?, + i2osp(i, 2)?, + serialize(&c_slice[i].to_arr().to_vec(), 2)?, + serialize(&d_slice[i].to_arr().to_vec(), 2)?, + serialize(&composite_dst, 2)?, + ] + .concat(); + let dst = [ + STR_HASH_TO_SCALAR, + &CS::get_context_string(Mode::Verifiable)?, + ] + .concat(); + let di = CS::Group::hash_to_scalar::(&h2_input, &dst)?; + m = c_slice[i] * &di + &m; + z = match k_option { + Some(_) => z, + None => d_slice[i] * &di + &z, + }; + } + + z = match k_option { + Some(k) => m * &k, + None => z, + }; + + Ok((m, z)) } /////////// @@ -133,33 +460,58 @@ mod tests { type Hash = Sha512; } - fn prf(input: &[u8], oprf_key: &[u8]) -> GenericArray::OutputSize> { + fn prf( + input: &[u8], + oprf_key: &[u8], + info: &[u8], + ) -> GenericArray::OutputSize> { let dst = [ - STR_VOPRF, - &RistrettoPoint::get_context_string(MODE_BASE).unwrap(), + STR_HASH_TO_GROUP, + &Ristretto255Sha512::get_context_string(Mode::Base).unwrap(), ] .concat(); let point = RistrettoPoint::map_to_curve::(input, &dst).unwrap(); let scalar = RistrettoPoint::from_scalar_slice(GenericArray::from_slice(&oprf_key[..])).unwrap(); - let res = point * scalar; - finalize_after_unblind::(&input, res).unwrap() + let context = [ + STR_CONTEXT, + &Ristretto255Sha512::get_context_string(Mode::Base).unwrap(), + &serialize(info, 2).unwrap(), + ] + .concat(); + let dst = [ + STR_HASH_TO_SCALAR, + &Ristretto255Sha512::get_context_string(Mode::Base).unwrap(), + ] + .concat(); + let m = <::Group as Group>::hash_to_scalar::< + ::Hash, + >(&context, &dst) + .unwrap(); + + let res = point + * &<::Group as Group>::scalar_invert(&(scalar + m)); + + finalize_after_unblind::(&input, res, info, Mode::Base).unwrap() } #[test] fn oprf_retrieval() { let input = b"hunter2"; + let info = b"info"; let mut rng = OsRng; - let (client, alpha) = Client::::blind(&input[..], &mut rng).unwrap(); + let (client, alpha) = + NonVerifiableClient::::blind(&input[..], &mut rng).unwrap(); 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, ]; - let server = Server::::new_with_key(&oprf_key_bytes).unwrap(); - let beta = server.evaluate(alpha); - let res = client.finalize(beta).unwrap(); - let res2 = prf(&input[..], &oprf_key_bytes); + let server = + NonVerifiableServer::::new_with_key(&oprf_key_bytes).unwrap(); + let beta = server.evaluate(alpha, info).unwrap(); + let res = client.finalize(beta, info).unwrap(); + let res2 = prf(&input[..], &oprf_key_bytes, info); assert_eq!(res, res2); } @@ -168,16 +520,19 @@ mod tests { let mut rng = OsRng; let mut input = alloc::vec![0u8; 64]; rng.fill_bytes(&mut input); - let (client, alpha) = Client::::blind(&input, &mut rng).unwrap(); - let res = client.finalize(alpha).unwrap(); + let info = b"info"; + let (client, alpha) = + NonVerifiableClient::::blind(&input, &mut rng).unwrap(); + let res = client.finalize(alpha, info).unwrap(); let dst = [ - STR_VOPRF, - &RistrettoPoint::get_context_string(MODE_BASE).unwrap(), + STR_HASH_TO_GROUP, + &Ristretto255Sha512::get_context_string(Mode::Base).unwrap(), ] .concat(); let point = RistrettoPoint::map_to_curve::(&input, &dst).unwrap(); - let res2 = finalize_after_unblind::(&input, point).unwrap(); + let res2 = + finalize_after_unblind::(&input, point, info, Mode::Base).unwrap(); assert_eq!(res, res2); }