From aebaab39e18a1c114e2aaae62ec9061d49f7a78a Mon Sep 17 00:00:00 2001
From: Piotr Roslaniec
Date: Fri, 19 Jan 2024 15:19:44 +0100
Subject: [PATCH] fix: prevent precomputed shares from being created with
inapprioriate variant
---
ferveo-wasm/examples/node/src/main.test.ts | 24 +++++----------
ferveo-wasm/tests/node.rs | 34 ++++++++--------------
ferveo/src/api.rs | 10 +++++--
ferveo/src/bindings_python.rs | 5 ++++
ferveo/src/lib.rs | 4 +++
5 files changed, 37 insertions(+), 40 deletions(-)
diff --git a/ferveo-wasm/examples/node/src/main.test.ts b/ferveo-wasm/examples/node/src/main.test.ts
index 28144861..047beeb5 100644
--- a/ferveo-wasm/examples/node/src/main.test.ts
+++ b/ferveo-wasm/examples/node/src/main.test.ts
@@ -22,11 +22,8 @@ const genEthAddr = (i: number) => {
return EthereumAddress.fromString(ethAddr);
};
-function setupTest() {
- const tau = 1;
- const sharesNum = 4;
- const threshold = Math.floor((sharesNum * 2) / 3);
-
+const tau = 1;
+function setupTest(sharesNum :number, threshold: number) {
const validatorKeypairs: Keypair[] = [];
const validators: Validator[] = [];
for (let i = 0; i < sharesNum; i++) {
@@ -63,9 +60,6 @@ function setupTest() {
const ciphertext = ferveoEncrypt(msg, aad, dkg.publicKey());
return {
- tau,
- sharesNum,
- threshold,
validatorKeypairs,
validators,
dkg,
@@ -79,17 +73,16 @@ function setupTest() {
// This test suite replicates tests from ferveo-wasm/tests/node.rs
describe("ferveo-wasm", () => {
it("simple tdec variant", () => {
+ const sharesNum = 4;
+ const threshold = 3;
const {
- tau,
- sharesNum,
- threshold,
validatorKeypairs,
validators,
messages,
msg,
aad,
ciphertext,
- } = setupTest();
+ } = setupTest(sharesNum, threshold);
// Having aggregated the transcripts, the validators can now create decryption shares
const decryptionShares: DecryptionShareSimple[] = [];
@@ -128,17 +121,16 @@ describe("ferveo-wasm", () => {
});
it("precomputed tdec variant", () => {
+ const sharesNum = 4;
+ const threshold = sharesNum; // threshold is equal to sharesNum in precomputed variant
const {
- tau,
- sharesNum,
- threshold,
validatorKeypairs,
validators,
messages,
msg,
aad,
ciphertext,
- } = setupTest();
+ } = setupTest(sharesNum, threshold);
// Having aggregated the transcripts, the validators can now create decryption shares
const decryptionShares: DecryptionSharePrecomputed[] = [];
diff --git a/ferveo-wasm/tests/node.rs b/ferveo-wasm/tests/node.rs
index 4ac71429..68e5f641 100644
--- a/ferveo-wasm/tests/node.rs
+++ b/ferveo-wasm/tests/node.rs
@@ -7,9 +7,6 @@ use itertools::zip_eq;
use wasm_bindgen_test::*;
type TestSetup = (
- u32,
- u32,
- u32,
Vec,
Vec,
ValidatorArray,
@@ -19,11 +16,9 @@ type TestSetup = (
Ciphertext,
);
-fn setup_dkg() -> TestSetup {
- let tau = 1;
- let shares_num: u32 = 16;
- let security_threshold = shares_num * 2 / 3;
+const TAU: u32 = 0;
+fn setup_dkg(shares_num: u32, security_threshold: u32) -> TestSetup {
let validator_keypairs = (0..shares_num as usize)
.map(gen_keypair)
.collect::>();
@@ -38,7 +33,7 @@ fn setup_dkg() -> TestSetup {
// validator, including themselves
let messages = validators.iter().map(|sender| {
let dkg = Dkg::new(
- tau,
+ TAU,
shares_num,
security_threshold,
&validators_js,
@@ -54,7 +49,7 @@ fn setup_dkg() -> TestSetup {
// every validator can aggregate the transcripts
let mut dkg = Dkg::new(
- tau,
+ TAU,
shares_num,
security_threshold,
&validators_js,
@@ -80,9 +75,6 @@ fn setup_dkg() -> TestSetup {
let ciphertext = ferveo_encrypt(&msg, &aad, &dkg.public_key()).unwrap();
(
- tau,
- shares_num,
- security_threshold,
validator_keypairs,
validators,
validators_js,
@@ -95,10 +87,9 @@ fn setup_dkg() -> TestSetup {
#[wasm_bindgen_test]
fn tdec_simple() {
+ let shares_num = 16;
+ let security_threshold = 10;
let (
- tau,
- shares_num,
- security_threshold,
validator_keypairs,
validators,
validators_js,
@@ -106,13 +97,13 @@ fn tdec_simple() {
msg,
aad,
ciphertext,
- ) = setup_dkg();
+ ) = setup_dkg(shares_num, security_threshold);
// Having aggregated the transcripts, the validators can now create decryption shares
let decryption_shares = zip_eq(validators, validator_keypairs)
.map(|(validator, keypair)| {
let mut dkg = Dkg::new(
- tau,
+ TAU,
shares_num,
security_threshold,
&validators_js,
@@ -149,10 +140,9 @@ fn tdec_simple() {
#[wasm_bindgen_test]
fn tdec_precomputed() {
+ let shares_num = 16;
+ let security_threshold = shares_num; // Must be equal to shares_num in precomputed variant
let (
- tau,
- shares_num,
- security_threshold,
validator_keypairs,
validators,
validators_js,
@@ -160,13 +150,13 @@ fn tdec_precomputed() {
msg,
aad,
ciphertext,
- ) = setup_dkg();
+ ) = setup_dkg(shares_num, security_threshold);
// Having aggregated the transcripts, the validators can now create decryption shares
let decryption_shares = zip_eq(validators, validator_keypairs)
.map(|(validator, keypair)| {
let mut dkg = Dkg::new(
- tau,
+ TAU,
shares_num,
security_threshold,
&validators_js,
diff --git a/ferveo/src/api.rs b/ferveo/src/api.rs
index 0a8bf2aa..3c2295d1 100644
--- a/ferveo/src/api.rs
+++ b/ferveo/src/api.rs
@@ -309,6 +309,14 @@ impl AggregatedTranscript {
aad: &[u8],
validator_keypair: &Keypair,
) -> Result {
+ if dkg.0.dkg_params.shares_num()
+ != dkg.0.dkg_params.security_threshold()
+ {
+ return Err(Error::InvalidDkgParametersForPrecomputedVariant(
+ dkg.0.dkg_params.shares_num(),
+ dkg.0.dkg_params.security_threshold(),
+ ));
+ }
let domain_points: Vec<_> = dkg
.0
.domain
@@ -455,8 +463,6 @@ mod test_ferveo_api {
let rng = &mut StdRng::seed_from_u64(0);
// In precomputed variant, the security threshold is equal to the number of shares
- // TODO: Refactor DKG constructor to not require security threshold or this case.
- // Or figure out a different way to simplify the precomputed variant API.
let security_threshold = shares_num;
let (messages, validators, validator_keypairs) =
diff --git a/ferveo/src/bindings_python.rs b/ferveo/src/bindings_python.rs
index 411b42c5..f897c8f6 100644
--- a/ferveo/src/bindings_python.rs
+++ b/ferveo/src/bindings_python.rs
@@ -104,6 +104,11 @@ impl From for PyErr {
"{index}"
))
},
+ Error::InvalidDkgParametersForPrecomputedVariant(num_shares, security_threshold) => {
+ InvalidDkgParameters::new_err(format!(
+ "num_shares: {num_shares}, security_threshold: {security_threshold}"
+ ))
+ },
},
_ => default(),
}
diff --git a/ferveo/src/lib.rs b/ferveo/src/lib.rs
index 394afb1a..c316c815 100644
--- a/ferveo/src/lib.rs
+++ b/ferveo/src/lib.rs
@@ -114,6 +114,10 @@ pub enum Error {
/// Failed to access a share for a given share index
#[error("Invalid share index: {0}")]
InvalidShareIndex(u32),
+
+ /// Failed to produce a precomputed variant decryption share
+ #[error("Invalid DKG parameters for precomputed variant: number of shares {0}, threshold {1}")]
+ InvalidDkgParametersForPrecomputedVariant(u32, u32),
}
pub type Result = std::result::Result;