From 671d1180a238bfbcdd0e67af17ffc9df2566b231 Mon Sep 17 00:00:00 2001 From: Kevin Lewi Date: Wed, 15 Sep 2021 11:38:13 -0700 Subject: [PATCH] Adding test vector support for verifiable mode (#4) --- src/errors.rs | 22 +- src/tests/voprf_test_vectors.rs | 420 ++++++++++++++++++++++---------- src/voprf.rs | 228 ++++++++++++----- 3 files changed, 462 insertions(+), 208 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index 506a6d8..f1f0a9c 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -15,15 +15,6 @@ use displaydoc::Display; pub enum InternalError { /// Could not parse byte sequence for key InvalidByteSequence, - /// Invalid length for {name}: expected {len}, but is actually {actual_len}. - SizeError { - /// name - name: &'static str, - /// length - len: usize, - /// actual - actual_len: usize, - }, /// Could not decompress point. PointError, /// Computing the hash-to-curve function failed @@ -39,22 +30,14 @@ pub enum InternalError { MismatchedLengthsForCompositeInputs, /// In verifiable mode, occurs when the proof failed to verify ProofVerificationError, + /// Encountered insufficient bytes when attempting to deserialize + SizeError, } impl Debug for InternalError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { Self::InvalidByteSequence => f.debug_tuple("InvalidByteSequence").finish(), - Self::SizeError { - name, - len, - actual_len, - } => f - .debug_struct("SizeError") - .field("name", name) - .field("len", len) - .field("actual_len", actual_len) - .finish(), Self::PointError => f.debug_tuple("PointError").finish(), Self::HashToCurveError => f.debug_tuple("HashToCurveError").finish(), Self::SerializationError => f.debug_tuple("SerializationError").finish(), @@ -63,6 +46,7 @@ impl Debug for InternalError { .debug_tuple("MismatchedLengthsForCompositeInputs") .finish(), Self::ProofVerificationError => f.debug_tuple("ProofVerificationError").finish(), + Self::SizeError => f.debug_tuple("SizeError").finish(), } } } diff --git a/src/tests/voprf_test_vectors.rs b/src/tests/voprf_test_vectors.rs index 124fb9f..be1f7fb 100644 --- a/src/tests/voprf_test_vectors.rs +++ b/src/tests/voprf_test_vectors.rs @@ -7,7 +7,9 @@ use crate::ciphersuite::CipherSuite; use crate::errors::*; use crate::group::Group; use crate::tests::{mock_rng::CycleRng, parser::*}; -use crate::voprf::{NonVerifiableClient, NonVerifiableServer}; +use crate::voprf::{ + NonVerifiableClient, NonVerifiableServer, Proof, VerifiableClient, VerifiableServer, +}; use alloc::string::ToString; use alloc::vec::Vec; use curve25519_dalek::ristretto::RistrettoPoint; @@ -19,40 +21,17 @@ use sha2::Sha512; struct VOPRFTestVectorParameters { seed: Vec, sksm: Vec, + pksm: Vec, input: Vec>, info: Vec, blind: Vec>, blinded_element: Vec>, evaluation_element: Vec>, + proof: Vec, + proof_random_scalar: Vec, output: Vec>, } -// Taken from https://github.com/cfrg/draft-irtf-cfrg-voprf/blob/master/draft-irtf-cfrg-voprf.md -// in base mode -#[cfg(feature = "p256")] -static OPRF_P256_SHA256: &[&str] = &[ - r#" - { - "sksm": "a1b2355828f2c76de6749af9d093bd9fe0f2cada3ec653cd9a6d3126a7a7827b", - "input": "00", - "blind": "5d9e7f6efd3093c32ecceabd57fb03cf760c926d2a7bfa265babf29ec98af0d0", - "blinded_element": "03e3c379698da853d9844098fa0ac676970d5ec24167b598714cd2ee188604ddd2", - "evaluation_element": "03ea54e8d095332d1a601a3f8a5013188aea036bf9b563236f7fd3b046908b42fd", - "output": "464e3e51e4086a824d9a2f939524d7069ae4072a788bc9d5daa0762b25826437" - } - "#, - r#" - { - "sksm": "a1b2355828f2c76de6749af9d093bd9fe0f2cada3ec653cd9a6d3126a7a7827b", - "input": "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a", - "blind": "825155ab61f17605af2ae2e935c78d857c9407bcd45128d57d338f1671b5fcbe", - "blinded_element": "030b40be181ffbb3c3ae4a4911287c43261f5e4034781def69c51608f372a02102", - "evaluation_element": "03115ad70ea55dbb4006da0ee3589a3582f31ef9cd143996d1e31a25ad3abdcf6f", - "output": "b597d58c843d0f9d2712121b0a3e2912ebee1c829eed3089eade9af4359ab275" - } - "#, -]; - static OPRF_TEST_VECTORS: &str = r#" ## OPRF(ristretto255, SHA-512) @@ -119,10 +98,10 @@ BlindedElement = 3a0a53f2c57e5ee0d89e394087f8e5f95b24159db01c31933a0 7f0e6414c954d EvaluationElement = f8a50ed35a477b0cde91d926e1bc5ae59b97d5bd0dda51a7 28b0f036ec557d79 -EvaluationProofC = 7a5375eb1dbad259431f5c294e816a1c1483c279748da1a75 -d91f8a81438ea08 -EvaluationProofS = 355d4087d4d848b46878dcc8fb5849ac7a09133382c2c6129 -564a7f7b4b7bf01 +Proof = 7a5375eb1dbad259431f5c294e816a1c1483c279748da1a75d91f8a81438 +ea08355d4087d4d848b46878dcc8fb5849ac7a09133382c2c6129564a7f7b4b7bf01 +ProofRandomScalar = 019cbd1d7420292528f8cdd62f339fdabb602f04a95dac9d +bcec831b8c681a09 Output = 4b2ff4c984985829c3cd9d90c255cdc0d6b61c4c0aafa9215769d51cf7d eb01472ba945928a8305e010f12b7dcc75a9dc2460439e6297d57dc2ce7ca0abaae1 a @@ -139,10 +118,10 @@ BlindedElement = a86dd4544d0f3ea973926054230767dff16016215f2d73f26d3 f86a81f38cf1a EvaluationElement = 9e47810f1de1b57ebe163a95c170ec165a2063f872155c37 6d94e8de2157af70 -EvaluationProofC = 61075125d851d5164b0aa1a4d5ddeebaf097266450ac60195 -79af5f7abd19008 -EvaluationProofS = 8eb0f6f1e7f9d8bfddbc21ae3c25a065e6c4e797d15f345ed -4fb9ee468d24c0a +Proof = 61075125d851d5164b0aa1a4d5ddeebaf097266450ac6019579af5f7abd1 +90088eb0f6f1e7f9d8bfddbc21ae3c25a065e6c4e797d15f345ed4fb9ee468d24c0a +ProofRandomScalar = 74ae06fd50d5f26c2519bd7b184f45dd3ef2cb50197d42df +9d013f7d6c312a0b Output = fe1fb7fa49c37dc7cd31d64859b4a2e6ae0cef294f2764e6f12f7d809f2 18047d1fde147cf69807b8971fb2c316eb572be2b5bf491813bfec0a20668d6d07b0 b @@ -162,10 +141,10 @@ BlindedElement = c24645d6378a4a86ec4682a8d86f368b1e7db870fd709a45102 EvaluationElement = 3afe48eab00493eb1b073e95f57a456cde9aefe463dd1e6d 0144bf6e99ce411c,daaf9421318fd2c7fcdf369cb348748cf4dd177cce30ee4d13c eb1644b85b653 -EvaluationProofC = 601381ecbe127ada04c057b8b1fc21d912f71e49252780dd0 -d0ac768b233ce03 -EvaluationProofS = 5f9b489a994c1d14b92d603ebcffee4f5cfadc953f69bb626 -48c6e662613ae00 +Proof = 601381ecbe127ada04c057b8b1fc21d912f71e49252780dd0d0ac768b233 +ce035f9b489a994c1d14b92d603ebcffee4f5cfadc953f69bb62648c6e662613ae00 +ProofRandomScalar = 3af5aec325791592eee4a8860522f8444c8e71ac33af5186 +a9706137886dce08 Output = 4b2ff4c984985829c3cd9d90c255cdc0d6b61c4c0aafa9215769d51cf7d eb01472ba945928a8305e010f12b7dcc75a9dc2460439e6297d57dc2ce7ca0abaae1 a,fe1fb7fa49c37dc7cd31d64859b4a2e6ae0cef294f2764e6f12f7d809f218047d1 @@ -237,10 +216,12 @@ BlindedElement = d0b8e2eecad2816d45c1f8a072fe6db77d18f4b26f0889c98e2 ef856ac5df82090c1fbeac9c8e732f192b66c3b4c3f1e446ab8910c86be2f EvaluationElement = d29849d8ad1e651328e8119003debd9ecd54cc786a5eb8ae ea56487ffc09120e98792f9475605488d16623b8e3cfa5af1ec27e76bc841b75 -EvaluationProofC = 8b3b8f0c9eb22527e419f5a03d4d3f34cf725837424a38c5b -4f88c7759f7a54bade57b7930bfeff051be9bfeaabc8976ed407398e0ce462a -EvaluationProofS = 062e068a8d57bc1c411bc42fe714626cfb92ad854a56636c2 -b83f2b5215c2ff531b22e4d37031523db203556959e275b46b84303ed23fc37 +Proof = 8b3b8f0c9eb22527e419f5a03d4d3f34cf725837424a38c5b4f88c7759f7 +a54bade57b7930bfeff051be9bfeaabc8976ed407398e0ce462a062e068a8d57bc1c +411bc42fe714626cfb92ad854a56636c2b83f2b5215c2ff531b22e4d37031523db20 +3556959e275b46b84303ed23fc37 +ProofRandomScalar = 1b3f5a55b2f18f8c53d4ecf2e1c27e1028f1c345bb504486 +4aa9dd8439d7520a7ba6183d50ef08bdf6c781aa465660c93e8195a8d231b62f Output = 1ff5c5c2c081c76006b52c45f79728882dc48962036ea7d4d5097b04e93 9ae81118a7fe5f0a66a6131bef18b9cd998150f10c62619ec4c2d223ea57dc67f153 d @@ -257,10 +238,12 @@ BlindedElement = 0e7ddd85c8bc5382e908241c6151afe23a41e0396759b5e38a9 affd996cd822bca242a499793555fc15f07bffdaaa93b42568b307fbdca0f EvaluationElement = 4c81e29e8a9502fa02e00cb09cf40d9b98988ac9b4bce7cc a0656caeb0926b59c7000d7fe6c5dd814f831864547d2360d223a50077bd04fe -EvaluationProofC = 74fc8fbf2e669dc5d25898ea8ce45d1d3eb97edb4b7c3cee3 -9865a3c66da6b7bad4ad3e77794d6f5e82fa8a645b9b973a8612bfcd1194302 -EvaluationProofS = f700ee3433e876d83f96bb70f19ff292605ad4c9466fd71db -c2ed22ade0130574e5ee343ef45d42e834a11a19fd6f5b1b5ef910bcccf731b +Proof = 74fc8fbf2e669dc5d25898ea8ce45d1d3eb97edb4b7c3cee39865a3c66da +6b7bad4ad3e77794d6f5e82fa8a645b9b973a8612bfcd1194302f700ee3433e876d8 +3f96bb70f19ff292605ad4c9466fd71dbc2ed22ade0130574e5ee343ef45d42e834a +11a19fd6f5b1b5ef910bcccf731b +ProofRandomScalar = 2f2e9955be83a4b25743ebd3618d4fad8b7288477da50bed +9befa58af639ddd950fec34205f8a4f166fadcb8fa71a3ffdd2e98f4c8ef5e26 Output = 2753e222528f1ee5fcc6ad4bf1ca953e5d3b47c1dfae85710f46a0a030c 07f59055e9b05dacb729a7ce41cd2ed782f8a76a1b3f74b40196aed0b6938b89c60f 9 @@ -283,10 +266,12 @@ EvaluationElement = 8a0d34fdb0b55121421546ff952c7bd3cbe469926ff9ad4f aeba243823955529eeae4f1a7a64cd055ec01baa041a99dfbe1a67ca4d59f93d,5e8 6e0b41cc88186ee0003baa46535e71acd98453b298976b92be2cca2646e88620f55d f6bf4754456dfd8d84f6889c17b5ff93052325a1a -EvaluationProofC = 1ff624a102b99771c76a9414e9b3f33127897d971bc84a922 -e464805e4a9f27b889922030adebbbd58e0ab618ade9c84bfe8aa226176f11f -EvaluationProofS = 432958ea1e6f69263aef51db9efb23ee504d233c17e9077c0 -373401da167637a1df4eafd9c2537c9f89c103f9e635931fe2042419dd9bd37 +Proof = 1ff624a102b99771c76a9414e9b3f33127897d971bc84a922e464805e4a9 +f27b889922030adebbbd58e0ab618ade9c84bfe8aa226176f11f432958ea1e6f6926 +3aef51db9efb23ee504d233c17e9077c0373401da167637a1df4eafd9c2537c9f89c +103f9e635931fe2042419dd9bd37 +ProofRandomScalar = a614f1894bcf6a1c7cef33909b794fe6e69a642b20f4c911 +8febffaf6b6a31471fe7794aa77ced123f07e56cc27de60b0ab106c0b8eab127 Output = 1ff5c5c2c081c76006b52c45f79728882dc48962036ea7d4d5097b04e93 9ae81118a7fe5f0a66a6131bef18b9cd998150f10c62619ec4c2d223ea57dc67f153 d,2753e222528f1ee5fcc6ad4bf1ca953e5d3b47c1dfae85710f46a0a030c07f5905 @@ -356,10 +341,10 @@ BlindedElement = 0222f5dba2da1ec7bd1086d0e04894ef1da1c11163daf376b2b c76cc51edb16815 EvaluationElement = 02f2767135f75f69b257675b38f2bcd50338a655a5092166 3c8942ca61ea7d3c29 -EvaluationProofC = ffa082fc9f9a287e7edc50e3ad879ee13aebd24b69124792b -df047c643f70af2 -EvaluationProofS = b50907b2fa188b90aff3b25e1d9abb02e9e2c8bfdc525c61c -a008428940fca64 +Proof = ffa082fc9f9a287e7edc50e3ad879ee13aebd24b69124792bdf047c643f7 +0af2b50907b2fa188b90aff3b25e1d9abb02e9e2c8bfdc525c61ca008428940fca64 +ProofRandomScalar = 70a5204b2b606f5a28328916e1e5ea5a17862d7a261fdd6d +959759758d5e34ac Output = c74d46cc93e578f7048bc6b852cd9bc1d9ebb90c586308f9202b9deedc8 94448 ~~~ @@ -375,10 +360,10 @@ BlindedElement = 02f84403d1ceb40a3668349f7c349f806d2c858785853324c66 7505018d13ee160 EvaluationElement = 0216d7d342ef50113244b444dfedaec78810959e40fef0a6 922658d44accb1e9c1 -EvaluationProofC = f496e58818c25ffb386f22ceb57a83da1200612b67aaa0760 -8b3375c25b297e0 -EvaluationProofS = 3e67d1f6094a8012725dc63a0c2f4f870173b97a3daa03588 -f777655a087fbbf +Proof = f496e58818c25ffb386f22ceb57a83da1200612b67aaa07608b3375c25b2 +97e03e67d1f6094a8012725dc63a0c2f4f870173b97a3daa03588f777655a087fbbf +ProofRandomScalar = 3b9217801b5d51cef66d9fdbd94a53533e7c5057e09e2200 +65ea8c257c0dd606 Output = 90a9f5ff4208a5505d1b7ed65eb233bb61b4c999ffa0d8cd1d98fb717b9 2fe28 ~~~ @@ -397,10 +382,10 @@ BlindedElement = 02a840214a74345570dcadfc927e726901b257b447234fac509 EvaluationElement = 025991aac0b0c79bb1185c0b1e64964656634dfcd755cdf5 da9ee52be0b5d5f742,03319e3baba8fa7f60dab49ef0ba68b7a85bccb5d4968643e 2f029b6c0826911d1 -EvaluationProofC = 51b5ed453168480a2e95863cda1f4d28ad5bc91e8c9c75d78 -8569aea1679794a -EvaluationProofS = 642087db120a2b3ce839f57041801f37cd4a6c05b69b327b8 -77810293f7b09a8 +Proof = 51b5ed453168480a2e95863cda1f4d28ad5bc91e8c9c75d788569aea1679 +794a642087db120a2b3ce839f57041801f37cd4a6c05b69b327b877810293f7b09a8 +ProofRandomScalar = 8306b863276ae74049615162a416d507a6532c99c1ea3f03 +d05f6e78dc1edabe Output = c74d46cc93e578f7048bc6b852cd9bc1d9ebb90c586308f9202b9deedc8 94448,90a9f5ff4208a5505d1b7ed65eb233bb61b4c999ffa0d8cd1d98fb717b92fe 28 @@ -471,10 +456,11 @@ BlindedElement = 02a1f41323e91a6ac9fbbb5b8e4c7c58a4c5bcbaa4195557182 cd59e826dc847f1e077de1d402ac92eafe322461fc0d582 EvaluationElement = 03af3164f8721a57931f92884b43c58ff0ed1be249f7e1c9 3033a5909f0ffc59ed3fea9452ec5c9cfb865b8bd2e65cd209 -EvaluationProofC = 44108ca9b342f4d7e31a250aa9f41afb0de840e113dbb6bb8 -2b5e6735aef18a20867a63628be6e109d2d687e1faa8888 -EvaluationProofS = 270f1173bc6f916e21142096d23d17194edf844074922c287 -a50182f87bbb5fc3a966c8851dd6799ec5cfe59c7063c7f +Proof = 44108ca9b342f4d7e31a250aa9f41afb0de840e113dbb6bb82b5e6735aef +18a20867a63628be6e109d2d687e1faa8888270f1173bc6f916e21142096d23d1719 +4edf844074922c287a50182f87bbb5fc3a966c8851dd6799ec5cfe59c7063c7f +ProofRandomScalar = 90f67cafc0ffaa7a1e1d1ced3c477fea691e696032c8709c +86cbcda2b184ad0029d29abeabede9788d11782429bff297 Output = 065094c66d66b6541aa1e09d99e2fdaac727356e9cd1c18275b7127be51 eb1ce7f37ad5924f7425d60828c2d1acc69bef40d11423bba8f9e34478e04c437fbe 0 @@ -491,10 +477,11 @@ BlindedElement = 02b3465d70f76de3eaf6ecb8080490288f741c622c06d023bd1 80a55a2e3e4eaad08533651f9d278a3f59cec8277780303 EvaluationElement = 03a53e01901893585437cd48a1eea1188fc8e9275a80cf43 370a451c476dae3b84ca8c7bf44fcac2fa3eeab933b25da0c3 -EvaluationProofC = 5ebc467e78ae29f7d741221df0ee67285df72ec482fdc8e5b -de7e588b12fcba86f4f116c23ee6b32c0f38f2daac67e86 -EvaluationProofS = 9e53e7e0494cc883e4984daf10a55819bbb5ce7e9005f143b -3dda88d8a35649269a4658a98c81c814097d15a3dcf4dbe +Proof = 5ebc467e78ae29f7d741221df0ee67285df72ec482fdc8e5bde7e588b12f +cba86f4f116c23ee6b32c0f38f2daac67e869e53e7e0494cc883e4984daf10a55819 +bbb5ce7e9005f143b3dda88d8a35649269a4658a98c81c814097d15a3dcf4dbe +ProofRandomScalar = bb1876a7f7165ac7ec79bfd5213ea2e374252f29a6e19915 +f81b0c7dcea93ce6580e089ede31c1b6b5b33494581b4868 Output = 5f557169680da50500b5333a26bb2ba79256c0ecc351051d32cac540920 267a40b246deb286c9ecb0025dede808465f85d6a5e75aca61088533b306d8646c92 c @@ -516,10 +503,11 @@ EvaluationElement = 03f9a8c81c108201888eb86348c6f80691d99425272972b5 bf41d3038af0eeb04d60edd9ea288625a7166a8c17cea0083f,02abb31980533dbf7 eb5fee0a8969089b3e16585a2cd41a34067592a2021b1b4ea3d1cef3e7c87a6f284c 0e45546c92d98 -EvaluationProofC = f0f7bd2723c3460d5c5ab03092c6861fb34253470ef430dac -9aeac6ce48984b28d91178061cba02e3e911c4aa97229d5 -EvaluationProofS = 19755db385ddd08064fdf8405897d1dea472688934088505e -89dcff91081fec1d2e37c1d4c5a9dddbdd358aa89f63b46 +Proof = f0f7bd2723c3460d5c5ab03092c6861fb34253470ef430dac9aeac6ce489 +84b28d91178061cba02e3e911c4aa97229d519755db385ddd08064fdf8405897d1de +a472688934088505e89dcff91081fec1d2e37c1d4c5a9dddbdd358aa89f63b46 +ProofRandomScalar = 1b538ff23749be19e92df82df1acd3f606cc9faa9dc7ab25 +1997738a3a232f352c2059c25684e6ccea420f8d0c793fa0 Output = 065094c66d66b6541aa1e09d99e2fdaac727356e9cd1c18275b7127be51 eb1ce7f37ad5924f7425d60828c2d1acc69bef40d11423bba8f9e34478e04c437fbe 0,5f557169680da50500b5333a26bb2ba79256c0ecc351051d32cac540920267a40b @@ -605,12 +593,13 @@ BlindedElement = 0200357f949a0a0bdfeb682734dbdeb778f3845045617b21436 EvaluationElement = 0201d636bac3f77c1091b337daae32259a3eacd57e3c0fb1 444fe5ce22af6acdcef4a46a2b5e169aa8d0e26ec2a3621c15dd366ba1978dae761c 1ef3dac63c60cbee88 -EvaluationProofC = 011ebe27ebc79e5679b643c6b3a51333499c7abee86c09218 -1c0a8e7e539e0ba30b1c128666708c753696ace2aa789c4975b0b80d6241a1dafe85 -c39a7338d1e20d0 -EvaluationProofS = 0131c8a81b5f64209f8fe53e8c6a00789a893f20596198e25 -21275e05d92529808e9f54030fc8be2ce78c6df0d29e6fd7d8e623e0ccc7b19b1944 -93dacd2a4eb3a32 +Proof = 011ebe27ebc79e5679b643c6b3a51333499c7abee86c092181c0a8e7e539 +e0ba30b1c128666708c753696ace2aa789c4975b0b80d6241a1dafe85c39a7338d1e +20d00131c8a81b5f64209f8fe53e8c6a00789a893f20596198e2521275e05d925298 +08e9f54030fc8be2ce78c6df0d29e6fd7d8e623e0ccc7b19b194493dacd2a4eb3a32 +ProofRandomScalar = 00ce4f0d824939827888f4c28773466f3c0a05741260040b +c9f302a4fea13f1d8f2f6b92a02a32d5eb06f81de7960470f06169bee12cf47965b7 +2a59946ca3879670 Output = c51295e2a03ba59f1538734316e0d70dd81f95daba2f7b5ac4906c56ce8 79d6cef8f583433c981a182a52dd568811b073f65fc1124941f344cc9dd3b3880f29 5 @@ -630,12 +619,13 @@ BlindedElement = 030185e431f056e75ba7fac49da70790031daa333d16f05e1de EvaluationElement = 02000859e1abc2ed28086b854ec5ae72311244fdeedf81d7 69af6a6f2c83f00fa48df1f1a0c0b6fac84cc654b7757ac042107a6b3043e483bb3b 74de5d6c301b20e8f6 -EvaluationProofC = 01629dd5af14c7414801d879b1018ce06bcc5c5d0a64ca422 -b76aaa531c8ecca630919fb4b51fa60fdc215f73e67e8d617d55ca6a227343d434d5 -e0f487567f85bfa -EvaluationProofS = 016959443267bb7d9a5c5e5b1c4d20026394b4edaca7dfbc1 -aa3b3c2020cf99579cf276c0e84f0cb5a820226fa3b81d42de2db39d8412642e7042 -8e485a61ee9d760 +Proof = 01629dd5af14c7414801d879b1018ce06bcc5c5d0a64ca422b76aaa531c8 +ecca630919fb4b51fa60fdc215f73e67e8d617d55ca6a227343d434d5e0f487567f8 +5bfa016959443267bb7d9a5c5e5b1c4d20026394b4edaca7dfbc1aa3b3c2020cf995 +79cf276c0e84f0cb5a820226fa3b81d42de2db39d8412642e70428e485a61ee9d760 +ProofRandomScalar = 00b5dfc19eb96faba6382ec845097904db87240b9dd47b1e +487ec625f11a7ba2cc3de74c5078a81806f74dd65065273c5bd886c7f87ff8c5f39f +90320718eff747e3 Output = 7462f460340a52f7b7609c5e1c5e2d5334d43da7631cb549bb65163a05d 1b2e936669e52e66c92da4b2e24fff3c118c62787577c01d2885567b476c13011057 1 @@ -661,12 +651,13 @@ EvaluationElement = 0300abdee910f144c3be460e724c11626e1f9986f72e2c43 0c4d545d0914413ea2,02019696f91dcc178bbe6b97f822cdc4052f9b94852ff6023 f6068848f867df40e54a5f1525e7fafa383e82fe36bf3c74427b51903032d0f89876 05bf24ee003f37693 -EvaluationProofC = 008fa896b69c1efc4e9c6bdfd0b149444532d5ba3bfd957cf -7cd71c374d3a1cca25f17b60616164377b0734243bc878e17d3ecab36b3e3565b5c6 -218dae92d40c0be -EvaluationProofS = 018707381f6f4b0153044737030b5d9851c15609532da8932 -c1fa1f4901dba05a4118d25142344f9ea1465c907eb13d908a45d8b98265eac48819 -a04cae859b0643a +Proof = 008fa896b69c1efc4e9c6bdfd0b149444532d5ba3bfd957cf7cd71c374d3 +a1cca25f17b60616164377b0734243bc878e17d3ecab36b3e3565b5c6218dae92d40 +c0be018707381f6f4b0153044737030b5d9851c15609532da8932c1fa1f4901dba05 +a4118d25142344f9ea1465c907eb13d908a45d8b98265eac48819a04cae859b0643a +ProofRandomScalar = 00d47b0d4ca4c64825ba085de242042b84d9ebe3b2e9de07 +678ff96713dfe16f40f2c662a56ed2db95e1e7bf2dea02bd1fa76e953a630772f68b +53baade9962d1646 Output = c51295e2a03ba59f1538734316e0d70dd81f95daba2f7b5ac4906c56ce8 79d6cef8f583433c981a182a52dd568811b073f65fc1124941f344cc9dd3b3880f29 5,7462f460340a52f7b7609c5e1c5e2d5334d43da7631cb549bb65163a05d1b2e936 @@ -726,11 +717,14 @@ fn populate_test_vectors(values: &JsonValue) -> VOPRFTestVectorParameters { VOPRFTestVectorParameters { seed: decode(&values, "seed").unwrap(), sksm: decode(&values, "skSm").unwrap(), + pksm: parse!(values, "pkSm"), 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(), + proof: parse!(values, "Proof"), + proof_random_scalar: parse!(values, "ProofRandomScalar"), output: decode_vec(&values, "Output").unwrap(), } } @@ -751,9 +745,21 @@ fn tests() -> Result<(), InternalError> { String::from("Base") ); - test_blind::(&ristretto_base_tvs)?; - test_evaluate::(&ristretto_base_tvs)?; - test_finalize::(&ristretto_base_tvs)?; + let ristretto_verifiable_tvs = json_to_test_vectors!( + rfc, + String::from("ristretto255, SHA-512"), + String::from("Verifiable") + ); + + test_base_seed_to_key::(&ristretto_base_tvs)?; + test_base_blind::(&ristretto_base_tvs)?; + test_base_evaluate::(&ristretto_base_tvs)?; + test_base_finalize::(&ristretto_base_tvs)?; + + test_verifiable_seed_to_key::(&ristretto_verifiable_tvs)?; + test_verifiable_blind::(&ristretto_verifiable_tvs)?; + test_verifiable_evaluate::(&ristretto_verifiable_tvs)?; + test_verifiable_finalize::(&ristretto_verifiable_tvs)?; #[cfg(feature = "p256")] { @@ -766,70 +772,222 @@ fn tests() -> Result<(), InternalError> { 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)?; + let p256_verifiable_tvs = json_to_test_vectors!( + rfc, + String::from("P-256, SHA-256"), + String::from("Verifiable") + ); + + test_base_seed_to_key::(&p256_base_tvs)?; + test_base_blind::(&p256_base_tvs)?; + test_base_evaluate::(&p256_base_tvs)?; + test_base_finalize::(&p256_base_tvs)?; + + test_verifiable_seed_to_key::(&p256_verifiable_tvs)?; + test_verifiable_blind::(&p256_verifiable_tvs)?; + test_verifiable_evaluate::(&p256_verifiable_tvs)?; + test_verifiable_finalize::(&p256_verifiable_tvs)?; } Ok(()) } -// Tests input -> blind, blinded_element -fn test_blind(tvs: &[VOPRFTestVectorParameters]) -> Result<(), InternalError> { +fn test_base_seed_to_key( + 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)?; + let server = NonVerifiableServer::::new_from_seed(¶meters.seed)?; assert_eq!( - ¶meters.blind[0], - &CS::Group::scalar_as_bytes(client.get_blind()).to_vec() + ¶meters.sksm, + &CS::Group::scalar_as_bytes(server.get_private_key()).to_vec() ); + } + Ok(()) +} + +fn test_verifiable_seed_to_key( + tvs: &[VOPRFTestVectorParameters], +) -> Result<(), InternalError> { + for parameters in tvs { + let server = VerifiableServer::::new_from_seed(¶meters.seed)?; + assert_eq!( - ¶meters.blinded_element[0], - &blinded_element.to_arr().to_vec() + ¶meters.sksm, + &CS::Group::scalar_as_bytes(server.get_private_key()).to_vec() ); + assert_eq!(¶meters.pksm, &server.get_public_key().to_arr().to_vec()); + } + Ok(()) +} + +// Tests input -> blind, blinded_element +fn test_base_blind( + tvs: &[VOPRFTestVectorParameters], +) -> Result<(), InternalError> { + for parameters in tvs { + for i in 0..parameters.input.len() { + let mut rng = CycleRng::new(parameters.blind[i].to_vec()); + let (client, blinded_element) = + NonVerifiableClient::::blind(¶meters.input[i], &mut rng)?; + + assert_eq!( + ¶meters.blind[i], + &CS::Group::scalar_as_bytes(client.get_blind()).to_vec() + ); + assert_eq!( + ¶meters.blinded_element[i], + &blinded_element.to_arr().to_vec() + ); + } + } + Ok(()) +} + +// Tests input -> blind, blinded_element +fn test_verifiable_blind( + tvs: &[VOPRFTestVectorParameters], +) -> Result<(), InternalError> { + for parameters in tvs { + for i in 0..parameters.input.len() { + let mut rng = CycleRng::new(parameters.blind[i].to_vec()); + let (client, blinded_element) = + VerifiableClient::::blind(¶meters.input[i], &mut rng)?; + + assert_eq!( + ¶meters.blind[i], + &CS::Group::scalar_as_bytes(client.get_blind()).to_vec() + ); + assert_eq!( + ¶meters.blinded_element[i], + &blinded_element.to_arr().to_vec() + ); + } } Ok(()) } // Tests sksm, blinded_element -> evaluation_element -fn test_evaluate(tvs: &[VOPRFTestVectorParameters]) -> Result<(), InternalError> { +fn test_base_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[0])) + for i in 0..parameters.input.len() { + 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[i], + )) .unwrap(), + ¶meters.info, + )?; + + assert_eq!( + ¶meters.evaluation_element[i], + &evaluation_element.to_arr().to_vec() + ); + } + } + Ok(()) +} + +fn test_verifiable_evaluate( + tvs: &[VOPRFTestVectorParameters], +) -> Result<(), InternalError> { + for parameters in tvs { + let mut rng = CycleRng::new(parameters.proof_random_scalar.clone()); + let server = VerifiableServer::::new_with_key(¶meters.sksm).unwrap(); + let (evaluation_elements, proof) = server.batch_evaluate( + &mut rng, + ¶meters + .blinded_element + .iter() + .map(|x| CS::Group::from_element_slice(GenericArray::from_slice(&x)).unwrap()) + .collect::>(), ¶meters.info, )?; - assert_eq!( - ¶meters.evaluation_element[0], - &evaluation_element.to_arr().to_vec() - ); + for i in 0..parameters.evaluation_element.len() { + assert_eq!( + ¶meters.evaluation_element[i], + &evaluation_elements[i].to_arr().to_vec(), + ); + } + + assert_eq!(¶meters.proof, &proof.serialize()); } Ok(()) } // Tests input, blind, evaluation_element -> output -fn test_finalize(tvs: &[VOPRFTestVectorParameters]) -> Result<(), InternalError> { +fn test_base_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[0], - )) - .unwrap(), - ); + for i in 0..parameters.input.len() { + let client = NonVerifiableClient::::from_data_and_blind( + ¶meters.input[i], + &::from_scalar_slice(&GenericArray::clone_from_slice( + ¶meters.blind[i], + )) + .unwrap(), + ); - let output = client.finalize( - ::from_element_slice(GenericArray::from_slice( - ¶meters.evaluation_element[0], - ))?, - ¶meters.info, - )?; + let output = client.finalize( + ::from_element_slice(GenericArray::from_slice( + ¶meters.evaluation_element[i], + ))?, + ¶meters.info, + )?; - assert_eq!(¶meters.output[0], &output.to_vec()); + assert_eq!(¶meters.output[i], &output.to_vec()); + } + } + Ok(()) +} + +fn test_verifiable_finalize( + tvs: &[VOPRFTestVectorParameters], +) -> Result<(), InternalError> { + for parameters in tvs { + let mut clients_and_evaluation_elements = vec![]; + + let mut clients = vec![]; + for i in 0..parameters.input.len() { + let client = VerifiableClient::::from_data_and_blind( + ¶meters.input[i], + &::from_scalar_slice(&GenericArray::clone_from_slice( + ¶meters.blind[i], + ))?, + &::from_element_slice(&GenericArray::clone_from_slice( + ¶meters.blinded_element[i], + ))?, + ); + clients.push(client.clone()); + } + + for i in 0..parameters.input.len() { + let evaluation_element = ::from_element_slice( + GenericArray::from_slice(¶meters.evaluation_element[i]), + )?; + + clients_and_evaluation_elements.push((&clients[i], evaluation_element)); + } + + let outputs = VerifiableClient::batch_finalize( + &clients_and_evaluation_elements, + Proof::deserialize(¶meters.proof)?, + CS::Group::from_element_slice(GenericArray::from_slice(¶meters.pksm))?, + ¶meters.info, + )?; + + assert_eq!( + parameters.output, + outputs + .iter() + .map(|arr| arr.to_vec()) + .collect::>>() + ); } Ok(()) } diff --git a/src/voprf.rs b/src/voprf.rs index 67d377e..0a13cc9 100644 --- a/src/voprf.rs +++ b/src/voprf.rs @@ -10,11 +10,11 @@ use crate::{ serialization::{i2osp, serialize}, }; use digest::Digest; -use generic_array::GenericArray; +use generic_array::{typenum::Unsigned, GenericArray}; use rand::{CryptoRng, RngCore}; use alloc::vec; -use generic_array::typenum::Unsigned; +use alloc::vec::Vec; static STR_HASH_TO_SCALAR: &[u8] = b"HashToScalar-"; static STR_HASH_TO_GROUP: &[u8] = b"HashToGroup-"; @@ -25,7 +25,7 @@ static STR_COMPOSITE: &[u8] = b"Composite-"; static STR_CHALLENGE: &[u8] = b"Challenge-"; pub struct NonVerifiableClient { - data: alloc::vec::Vec, + data: Vec, blind: ::Scalar, } @@ -35,7 +35,7 @@ impl NonVerifiableClient { input: &[u8], blinding_factor_rng: &mut R, ) -> Result<(Self, CS::Group), InternalError> { - let (blind, blinded_element) = blind::(input, blinding_factor_rng)?; + let (blind, blinded_element) = blind::(input, blinding_factor_rng, Mode::Base)?; Ok(( Self { data: input.to_vec(), @@ -49,12 +49,17 @@ impl NonVerifiableClient { /// the client unblinds the server's message. pub fn finalize( &self, - evaluated_element: CS::Group, + evaluation_element: CS::Group, info: &[u8], ) -> Result::OutputSize>, InternalError> { let unblinded_element = - evaluated_element * &::scalar_invert(&self.blind); - finalize_after_unblind::(&self.data, unblinded_element, info, Mode::Base) + evaluation_element * &::scalar_invert(&self.blind); + let outputs = finalize_after_unblind::( + &[(self.data.clone(), unblinded_element)], + info, + Mode::Base, + )?; + Ok(outputs[0].clone()) } #[cfg(test)] @@ -79,13 +84,24 @@ pub struct VerifiableClient { blinded_element: CS::Group, } +impl Clone for VerifiableClient { + fn clone(&self) -> Self { + Self { + data: self.data.clone(), + blind: self.blind, + blinded_element: self.blinded_element, + } + } +} + 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)?; + let (blind, blinded_element) = + blind::(input, blinding_factor_rng, Mode::Verifiable)?; Ok(( Self { data: input.to_vec(), @@ -100,20 +116,41 @@ impl VerifiableClient { /// the client unblinds the server's message. pub fn finalize( &self, - evaluated_element: CS::Group, + evaluation_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) + let outputs = Self::batch_finalize(&[(self, evaluation_element)], proof, pk, info)?; + Ok(outputs[0].clone()) + } + + #[allow(clippy::type_complexity)] + pub fn batch_finalize( + clients_and_evaluation_elements: &[(&VerifiableClient, CS::Group)], + proof: Proof, + pk: CS::Group, + info: &[u8], + ) -> Result::OutputSize>>, InternalError> { + let batch_items: Vec> = clients_and_evaluation_elements + .iter() + .map(|(client, evaluation_element)| BatchItems { + blind: client.blind, + evaluation_element: *evaluation_element, + blinded_element: client.blinded_element, + }) + .collect(); + + let unblinded_elements = verifiable_unblind(&batch_items, pk, proof, info)?; + + let inputs_and_unblinded_elements: Vec<(Vec, CS::Group)> = + clients_and_evaluation_elements + .iter() + .zip(unblinded_elements.iter()) + .map(|((client, _), &unblinded_element)| (client.data.clone(), unblinded_element)) + .collect(); + + finalize_after_unblind::(&inputs_and_unblinded_elements, info, Mode::Verifiable) } #[cfg(test)] @@ -137,14 +174,19 @@ impl VerifiableClient { } } -fn verifiable_unblind( +/// Only used in batching +struct BatchItems { blind: ::Scalar, - evaluated_element: CS::Group, + evaluation_element: CS::Group, blinded_element: CS::Group, +} + +fn verifiable_unblind( + batch_items: &[BatchItems], pk: CS::Group, proof: Proof, info: &[u8], -) -> Result { +) -> Result, InternalError> { let context = [ STR_CONTEXT, &CS::get_context_string(Mode::Verifiable)?, @@ -163,10 +205,19 @@ fn verifiable_unblind( let t = g * &m; let u = t + &pk; - verify_proof(g, u, evaluated_element, blinded_element, proof)?; + let blinds: Vec<::Scalar> = batch_items.iter().map(|x| x.blind).collect(); + let evaluation_elements: Vec = + batch_items.iter().map(|x| x.evaluation_element).collect(); + let blinded_elements: Vec = batch_items.iter().map(|x| x.blinded_element).collect(); - let unblinded_element = evaluated_element * &CS::Group::scalar_invert(&blind); - Ok(unblinded_element) + verify_proof(g, u, &evaluation_elements, &blinded_elements, proof)?; + + let unblinded_elements = blinds + .iter() + .zip(evaluation_elements.iter()) + .map(|(&blind, &x)| x * &CS::Group::scalar_invert(&blind)) + .collect(); + Ok(unblinded_elements) } pub struct NonVerifiableServer { @@ -192,6 +243,12 @@ impl NonVerifiableServer { Ok(Self { sk }) } + // Only used for tests + #[cfg(test)] + pub fn get_private_key(&self) -> ::Scalar { + 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( @@ -208,8 +265,8 @@ impl NonVerifiableServer { 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) + let evaluation_element = blinded_element * &CS::Group::scalar_invert(&t); + Ok(evaluation_element) } } @@ -243,6 +300,12 @@ impl VerifiableServer { Ok(Self { sk, pk }) } + // Only used for tests + #[cfg(test)] + pub fn get_private_key(&self) -> ::Scalar { + 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( @@ -251,23 +314,40 @@ impl VerifiableServer { blinded_element: CS::Group, info: &[u8], ) -> Result<(CS::Group, Proof), InternalError> { + let (evaluation_elements, proof) = self.batch_evaluate(rng, &[blinded_element], info)?; + Ok((evaluation_elements[0], proof)) + } + + pub fn batch_evaluate( + &self, + rng: &mut R, + blinded_elements: &[CS::Group], + info: &[u8], + ) -> Result<(Vec, Proof), InternalError> { let context = [ STR_CONTEXT, - &CS::get_context_string(Mode::Base)?, + &CS::get_context_string(Mode::Verifiable)?, &serialize(info, 2)?, ] .concat(); - let dst = [STR_HASH_TO_SCALAR, &CS::get_context_string(Mode::Base)?].concat(); + let dst = [ + STR_HASH_TO_SCALAR, + &CS::get_context_string(Mode::Verifiable)?, + ] + .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 evaluation_elements: Vec = blinded_elements + .iter() + .map(|&x| x * &CS::Group::scalar_invert(&t)) + .collect(); let g = CS::Group::base_point(); let u = g * &t; - let proof = generate_proof(rng, t, g, u, evaluated_element, blinded_element)?; + let proof = generate_proof(rng, t, g, u, &evaluation_elements, blinded_elements)?; - Ok((evaluated_element, proof)) + Ok((evaluation_elements, proof)) } pub fn get_public_key(&self) -> CS::Group { @@ -279,10 +359,11 @@ impl VerifiableServer { fn blind( input: &[u8], blinding_factor_rng: &mut R, + mode: Mode, ) -> 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 dst = [STR_HASH_TO_GROUP, &CS::get_context_string(mode)?].concat(); let mapped_point = ::map_to_curve::(input, &dst)?; let blinded_element = mapped_point * &blind; Ok((blind, blinded_element)) @@ -294,10 +375,10 @@ fn generate_proof( k: ::Scalar, a: CS::Group, b: CS::Group, - c: CS::Group, - d: CS::Group, + cs: &[CS::Group], + ds: &[CS::Group], ) -> Result, InternalError> { - let (m, z) = compute_composites::(Some(k), b, &[c], &[d])?; + let (m, z) = compute_composites::(Some(k), b, cs, ds)?; let r = CS::Group::random_nonzero_scalar(rng); let t2 = a * &r; @@ -319,14 +400,11 @@ fn generate_proof( &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); + let c_scalar = CS::Group::hash_to_scalar::(&h2_input, &hash_to_scalar_dst)?; + let s_scalar = r - &(c_scalar * &k); - Ok(Proof { - c_scalar: c, - s_scalar: s, - }) + Ok(Proof { c_scalar, s_scalar }) } pub struct Proof { @@ -334,15 +412,36 @@ pub struct Proof { s_scalar: ::Scalar, } +impl Proof { + pub fn serialize(&self) -> Vec { + [ + CS::Group::scalar_as_bytes(self.c_scalar), + CS::Group::scalar_as_bytes(self.s_scalar), + ] + .concat() + } + + pub fn deserialize(input: &[u8]) -> Result { + let scalar_len = ::ScalarLen::to_usize(); + if input.len() < scalar_len + scalar_len { + return Err(InternalError::SizeError); + } + Ok(Proof { + c_scalar: CS::Group::from_scalar_slice(GenericArray::from_slice(&input[..scalar_len]))?, + s_scalar: CS::Group::from_scalar_slice(GenericArray::from_slice(&input[scalar_len..]))?, + }) + } +} + #[allow(clippy::many_single_char_names)] fn verify_proof( a: CS::Group, b: CS::Group, - c: CS::Group, - d: CS::Group, + cs: &[CS::Group], + ds: &[CS::Group], proof: Proof, ) -> Result<(), InternalError> { - let (m, z) = compute_composites::(None, b, &[c], &[d])?; + let (m, z) = compute_composites::(None, b, cs, ds)?; let t2 = (a * &proof.s_scalar) + &(b * &proof.c_scalar); let t3 = (m * &proof.s_scalar) + &(z * &proof.c_scalar); @@ -370,21 +469,29 @@ fn verify_proof( } } +#[allow(clippy::type_complexity)] fn finalize_after_unblind( - input: &[u8], - unblinded_element: CS::Group, + inputs_and_unblinded_elements: &[(Vec, CS::Group)], info: &[u8], mode: Mode, -) -> Result::OutputSize>, InternalError> { +) -> 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)) + + let mut outputs = vec![]; + + for (input, unblinded_element) in inputs_and_unblinded_elements { + outputs.push(::digest( + &[ + serialize(input, 2)?, + serialize(info, 2)?, + serialize(&unblinded_element.to_arr().to_vec(), 2)?, + serialize(&finalize_dst, 2)?, + ] + .concat(), + )); + } + + Ok(outputs) } fn compute_composites( @@ -493,7 +600,8 @@ mod tests { let res = point * &<::Group as Group>::scalar_invert(&(scalar + m)); - finalize_after_unblind::(&input, res, info, Mode::Base).unwrap() + finalize_after_unblind::(&[(input.to_vec(), res)], info, Mode::Base) + .unwrap()[0] } #[test] @@ -531,8 +639,12 @@ mod tests { ] .concat(); let point = RistrettoPoint::map_to_curve::(&input, &dst).unwrap(); - let res2 = - finalize_after_unblind::(&input, point, info, Mode::Base).unwrap(); + let res2 = finalize_after_unblind::( + &[(input.to_vec(), point)], + info, + Mode::Base, + ) + .unwrap()[0]; assert_eq!(res, res2); }