Skip to content

Commit

Permalink
refactor(test): deduplicate test utils
Browse files Browse the repository at this point in the history
  • Loading branch information
piotr-roslaniec committed Jan 19, 2024
1 parent 66d25ae commit 3fe080e
Show file tree
Hide file tree
Showing 8 changed files with 242 additions and 265 deletions.
63 changes: 28 additions & 35 deletions ferveo/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ pub use ferveo_tdec::api::{
prepare_combine_simple, share_combine_precomputed, share_combine_simple,
Fr, G1Affine, G1Prepared, G2Affine, SecretBox, E,
};
use generic_array::{typenum::U48, GenericArray};
use generic_array::{
typenum::{Unsigned, U48},
GenericArray,
};
use rand::RngCore;
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
Expand Down Expand Up @@ -167,7 +170,7 @@ impl DkgPublicKey {
}

pub fn serialized_size() -> usize {
48
U48::to_usize()
}

/// Generate a random DKG public key.
Expand Down Expand Up @@ -399,12 +402,10 @@ mod test_ferveo_api {
use rand::{prelude::StdRng, SeedableRng};
use test_case::test_case;

use crate::{api::*, dkg::test_common::*};
use crate::{api::*, test_common::*};

type TestInputs = (Vec<ValidatorMessage>, Vec<Validator>, Vec<Keypair>);

const TAU: u32 = 1;

fn make_test_inputs(
rng: &mut StdRng,
tau: u32,
Expand Down Expand Up @@ -446,6 +447,7 @@ mod test_ferveo_api {
let dkg_pk = DkgPublicKey::random();
let serialized = dkg_pk.to_bytes().unwrap();
let deserialized = DkgPublicKey::from_bytes(&serialized).unwrap();
assert_eq!(serialized.len(), 48_usize);
assert_eq!(dkg_pk, deserialized);
}

Expand Down Expand Up @@ -476,10 +478,9 @@ mod test_ferveo_api {
let dkg_public_key = dkg.public_key();

// In the meantime, the client creates a ciphertext and decryption request
let msg = "my-msg".as_bytes().to_vec();
let aad: &[u8] = "my-aad".as_bytes();
let ciphertext =
encrypt(SecretBox::new(msg.clone()), aad, &dkg_public_key).unwrap();
encrypt(SecretBox::new(MSG.to_vec()), AAD, &dkg_public_key)
.unwrap();

// Having aggregated the transcripts, the validators can now create decryption shares
let decryption_shares: Vec<_> = izip!(&validators, &validator_keypairs)
Expand All @@ -501,7 +502,7 @@ mod test_ferveo_api {
.create_decryption_share_precomputed(
&dkg,
&ciphertext.header().unwrap(),
aad,
AAD,
validator_keypair,
)
.unwrap()
Expand All @@ -514,11 +515,11 @@ mod test_ferveo_api {
let shared_secret = share_combine_precomputed(&decryption_shares);
let plaintext = decrypt_with_shared_secret(
&ciphertext,
aad,
AAD,
&SharedSecret(shared_secret),
)
.unwrap();
assert_eq!(plaintext, msg);
assert_eq!(plaintext, MSG);

// Since we're using a precomputed variant, we need all the shares to be able to decrypt
// So if we remove one share, we should not be able to decrypt
Expand All @@ -528,7 +529,7 @@ mod test_ferveo_api {
let shared_secret = share_combine_precomputed(&decryption_shares);
let result = decrypt_with_shared_secret(
&ciphertext,
aad,
AAD,
&SharedSecret(shared_secret),
);
assert!(result.is_err());
Expand Down Expand Up @@ -562,10 +563,8 @@ mod test_ferveo_api {
let public_key = dkg.public_key();

// In the meantime, the client creates a ciphertext and decryption request
let msg = "my-msg".as_bytes().to_vec();
let aad: &[u8] = "my-aad".as_bytes();
let ciphertext =
encrypt(SecretBox::new(msg.clone()), aad, &public_key).unwrap();
encrypt(SecretBox::new(MSG.to_vec()), AAD, &public_key).unwrap();

// Having aggregated the transcripts, the validators can now create decryption shares
let decryption_shares: Vec<_> = izip!(&validators, &validator_keypairs)
Expand All @@ -585,7 +584,7 @@ mod test_ferveo_api {
.create_decryption_share_simple(
&dkg,
&ciphertext.header().unwrap(),
aad,
AAD,
validator_keypair,
)
.unwrap()
Expand All @@ -601,9 +600,9 @@ mod test_ferveo_api {

let shared_secret = combine_shares_simple(&decryption_shares);
let plaintext =
decrypt_with_shared_secret(&ciphertext, aad, &shared_secret)
decrypt_with_shared_secret(&ciphertext, AAD, &shared_secret)
.unwrap();
assert_eq!(plaintext, msg);
assert_eq!(plaintext, MSG);

// Let's say that we've only received `security_threshold - 1` shares
// In this case, we should not be able to decrypt
Expand All @@ -612,25 +611,22 @@ mod test_ferveo_api {

let shared_secret = combine_shares_simple(&decryption_shares);
let result =
decrypt_with_shared_secret(&ciphertext, aad, &shared_secret);
decrypt_with_shared_secret(&ciphertext, AAD, &shared_secret);
assert!(result.is_err());
}

#[test]
fn server_side_local_verification() {
let rng = &mut StdRng::seed_from_u64(0);

let security_threshold = 3;
let shares_num = 4;

let (messages, validators, _) =
make_test_inputs(rng, TAU, security_threshold, shares_num);
make_test_inputs(rng, TAU, SECURITY_THRESHOLD, SHARES_NUM);

// Now that every validator holds a dkg instance and a transcript for every other validator,
// every validator can aggregate the transcripts
let me = validators[0].clone();
let mut dkg =
Dkg::new(TAU, shares_num, security_threshold, &validators, &me)
Dkg::new(TAU, SHARES_NUM, SECURITY_THRESHOLD, &validators, &me)
.unwrap();

let local_aggregate = dkg.aggregate_transcripts(&messages).unwrap();
Expand All @@ -643,14 +639,11 @@ mod test_ferveo_api {
fn client_side_local_verification() {
let rng = &mut StdRng::seed_from_u64(0);

let security_threshold = 3;
let shares_num = 4;

let (messages, _, _) =
make_test_inputs(rng, TAU, security_threshold, shares_num);
make_test_inputs(rng, TAU, SECURITY_THRESHOLD, SHARES_NUM);

// We only need `security_threshold` transcripts to aggregate
let messages = &messages[..security_threshold as usize];
let messages = &messages[..SECURITY_THRESHOLD as usize];

// Create an aggregated transcript on the client side
let aggregated_transcript = AggregatedTranscript::new(messages);
Expand All @@ -659,27 +652,27 @@ mod test_ferveo_api {
// the aggregate from a side-channel or decide to persist it and verify it later

// Now, the client can verify the aggregated transcript
let result = aggregated_transcript.verify(shares_num, messages);
let result = aggregated_transcript.verify(SHARES_NUM, messages);
assert!(result.is_ok());
assert!(result.unwrap());

// Test negative cases

// Not enough transcripts
let not_enough_messages = &messages[..2];
assert!(not_enough_messages.len() < security_threshold as usize);
let not_enough_messages = &messages[..SECURITY_THRESHOLD as usize - 1];
assert!(not_enough_messages.len() < SECURITY_THRESHOLD as usize);
let insufficient_aggregate =
AggregatedTranscript::new(not_enough_messages);
let result = insufficient_aggregate.verify(shares_num, messages);
let result = insufficient_aggregate.verify(SHARES_NUM, messages);
assert!(result.is_err());

// Unexpected transcripts in the aggregate or transcripts from a different ritual
// Using same DKG parameters, but different DKG instances and validators
let (bad_messages, _, _) =
make_test_inputs(rng, TAU, security_threshold, shares_num);
make_test_inputs(rng, TAU, SECURITY_THRESHOLD, SHARES_NUM);
let mixed_messages = [&messages[..2], &bad_messages[..1]].concat();
let bad_aggregate = AggregatedTranscript::new(&mixed_messages);
let result = bad_aggregate.verify(shares_num, messages);
let result = bad_aggregate.verify(SHARES_NUM, messages);
assert!(result.is_err());
}
}
64 changes: 27 additions & 37 deletions ferveo/src/bindings_python.rs
Original file line number Diff line number Diff line change
Expand Up @@ -739,7 +739,7 @@ pub fn make_ferveo_py_module(py: Python<'_>, m: &PyModule) -> PyResult<()> {
mod test_ferveo_python {
use itertools::izip;

use crate::bindings_python::*;
use crate::{bindings_python::*, test_common::*};

type TestInputs = (Vec<ValidatorMessage>, Vec<Validator>, Vec<Keypair>);

Expand Down Expand Up @@ -785,21 +785,19 @@ mod test_ferveo_python {

#[test]
fn test_server_api_tdec_precomputed() {
let tau = 1;
let shares_num = 4;
// In precomputed variant, the security threshold is equal to the number of shares
let security_threshold = shares_num;
let security_threshold = SHARES_NUM;

let (messages, validators, validator_keypairs) =
make_test_inputs(tau, security_threshold, shares_num);
make_test_inputs(TAU, security_threshold, SHARES_NUM);

// Now that every validator holds a dkg instance and a transcript for every other validator,
// every validator can aggregate the transcripts

let me = validators[0].clone();
let mut dkg = Dkg::new(
tau,
shares_num,
TAU,
SHARES_NUM,
security_threshold,
validators.clone(),
&me,
Expand All @@ -811,24 +809,22 @@ mod test_ferveo_python {
let pvss_aggregated =
dkg.aggregate_transcripts(messages.clone()).unwrap();
assert!(pvss_aggregated
.verify(shares_num, messages.clone())
.verify(SHARES_NUM, messages.clone())
.unwrap());

// At this point, any given validator should be able to provide a DKG public key
let dkg_public_key = dkg.public_key();

// In the meantime, the client creates a ciphertext and decryption request
let msg: &[u8] = "my-msg".as_bytes();
let aad: &[u8] = "my-aad".as_bytes();
let ciphertext = encrypt(msg, aad, &dkg_public_key).unwrap();
let ciphertext = encrypt(MSG, AAD, &dkg_public_key).unwrap();

// Having aggregated the transcripts, the validators can now create decryption shares
let decryption_shares: Vec<_> = izip!(&validators, &validator_keypairs)
.map(|(validator, validator_keypair)| {
// Each validator holds their own instance of DKG and creates their own aggregate
let mut dkg = Dkg::new(
tau,
shares_num,
TAU,
SHARES_NUM,
security_threshold,
validators.clone(),
validator,
Expand All @@ -837,13 +833,13 @@ mod test_ferveo_python {
let aggregate =
dkg.aggregate_transcripts(messages.clone()).unwrap();
assert!(pvss_aggregated
.verify(shares_num, messages.clone())
.verify(SHARES_NUM, messages.clone())
.is_ok());
aggregate
.create_decryption_share_precomputed(
&dkg,
&ciphertext.header().unwrap(),
aad,
AAD,
validator_keypair,
)
.unwrap()
Expand All @@ -857,70 +853,64 @@ mod test_ferveo_python {
combine_decryption_shares_precomputed(decryption_shares);

let plaintext =
decrypt_with_shared_secret(&ciphertext, aad, &shared_secret)
decrypt_with_shared_secret(&ciphertext, AAD, &shared_secret)
.unwrap();
assert_eq!(plaintext, msg);
assert_eq!(plaintext, MSG);
}

#[test]
fn test_server_api_tdec_simple() {
let tau = 1;
let shares_num = 4;
let security_threshold = 3;

let (messages, validators, validator_keypairs) =
make_test_inputs(tau, security_threshold, shares_num);
make_test_inputs(TAU, SECURITY_THRESHOLD, SHARES_NUM);

// Now that every validator holds a dkg instance and a transcript for every other validator,
// every validator can aggregate the transcripts
let me = validators[0].clone();
let mut dkg = Dkg::new(
tau,
shares_num,
security_threshold,
TAU,
SHARES_NUM,
SECURITY_THRESHOLD,
validators.clone(),
&me,
)
.unwrap();

// Lets say that we've only receives `security_threshold` transcripts
let messages = messages[..security_threshold as usize].to_vec();
let messages = messages[..SECURITY_THRESHOLD as usize].to_vec();
let pvss_aggregated =
dkg.aggregate_transcripts(messages.clone()).unwrap();
assert!(pvss_aggregated
.verify(shares_num, messages.clone())
.verify(SHARES_NUM, messages.clone())
.unwrap());

// At this point, any given validator should be able to provide a DKG public key
let dkg_public_key = dkg.public_key();

// In the meantime, the client creates a ciphertext and decryption request
let msg: &[u8] = "my-msg".as_bytes();
let aad: &[u8] = "my-aad".as_bytes();
let ciphertext = encrypt(msg, aad, &dkg_public_key).unwrap();
let ciphertext = encrypt(MSG, AAD, &dkg_public_key).unwrap();

// Having aggregated the transcripts, the validators can now create decryption shares
let decryption_shares: Vec<_> = izip!(&validators, &validator_keypairs)
.map(|(validator, validator_keypair)| {
// Each validator holds their own instance of DKG and creates their own aggregate
let mut dkg = Dkg::new(
tau,
shares_num,
security_threshold,
TAU,
SHARES_NUM,
SECURITY_THRESHOLD,
validators.clone(),
validator,
)
.unwrap();
let aggregate =
dkg.aggregate_transcripts(messages.clone()).unwrap();
assert!(aggregate
.verify(shares_num, messages.clone())
.verify(SHARES_NUM, messages.clone())
.unwrap());
aggregate
.create_decryption_share_simple(
&dkg,
&ciphertext.header().unwrap(),
aad,
AAD,
validator_keypair,
)
.unwrap()
Expand All @@ -933,8 +923,8 @@ mod test_ferveo_python {
let shared_secret = combine_decryption_shares_simple(decryption_shares);

let plaintext =
decrypt_with_shared_secret(&ciphertext, aad, &shared_secret)
decrypt_with_shared_secret(&ciphertext, AAD, &shared_secret)
.unwrap();
assert_eq!(plaintext, msg);
assert_eq!(plaintext, MSG);
}
}
1 change: 0 additions & 1 deletion ferveo/src/bindings_wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,6 @@ impl Keypair {
}
}

/// Factory functions for testing
pub mod test_common {
use crate::bindings_wasm::*;

Expand Down
Loading

0 comments on commit 3fe080e

Please sign in to comment.