806 lines
28 KiB
Rust
806 lines
28 KiB
Rust
use crate::{
|
|
frost,
|
|
messages::{
|
|
validate::{MsgErr, Validate},
|
|
*,
|
|
},
|
|
verification_key,
|
|
};
|
|
use rand::thread_rng;
|
|
use serde_json;
|
|
use std::convert::TryFrom;
|
|
|
|
#[test]
|
|
fn validate_version() {
|
|
// A version number that we expect to be always invalid
|
|
const INVALID_VERSION: u8 = u8::MAX;
|
|
|
|
let setup = basic_setup();
|
|
|
|
let header = Header {
|
|
version: MsgVersion(INVALID_VERSION),
|
|
sender: setup.dealer,
|
|
receiver: setup.signer1,
|
|
};
|
|
|
|
let validate = Validate::validate(&header);
|
|
assert_eq!(validate, Err(MsgErr::WrongVersion));
|
|
|
|
let validate = Validate::validate(&Header {
|
|
version: constants::BASIC_FROST_SERIALIZATION,
|
|
sender: setup.dealer,
|
|
receiver: setup.signer1,
|
|
})
|
|
.err();
|
|
|
|
assert_eq!(validate, None);
|
|
}
|
|
|
|
#[test]
|
|
fn validate_sender_receiver() {
|
|
let setup = basic_setup();
|
|
|
|
let header = Header {
|
|
version: constants::BASIC_FROST_SERIALIZATION,
|
|
sender: setup.signer1,
|
|
receiver: setup.signer1,
|
|
};
|
|
|
|
let validate = Validate::validate(&header);
|
|
assert_eq!(validate, Err(MsgErr::SameSenderAndReceiver));
|
|
}
|
|
|
|
#[test]
|
|
fn validate_sharepackage() {
|
|
let setup = basic_setup();
|
|
let (mut shares, _pubkeys) =
|
|
frost::keygen_with_dealer(setup.num_signers, setup.threshold, setup.rng.clone()).unwrap();
|
|
|
|
let header = create_valid_header(setup.signer1, setup.signer2);
|
|
|
|
let group_public = VerificationKey::from(
|
|
verification_key::VerificationKey::try_from(shares[0].group_public.bytes).unwrap(),
|
|
);
|
|
let secret_share = Secret(shares[0].share.value.0.to_bytes());
|
|
|
|
let participants = vec![setup.signer1, setup.signer2];
|
|
shares.truncate(2);
|
|
let share_commitment = generate_share_commitment(&shares, participants);
|
|
|
|
let payload = Payload::SharePackage(SharePackage {
|
|
group_public,
|
|
secret_share: secret_share,
|
|
share_commitment: share_commitment,
|
|
});
|
|
let validate_payload = Validate::validate(&payload);
|
|
let valid_payload = validate_payload.expect("a valid payload").clone();
|
|
|
|
let message = Message {
|
|
header,
|
|
payload: valid_payload.clone(),
|
|
};
|
|
|
|
let validate_message = Validate::validate(&message);
|
|
assert_eq!(validate_message, Err(MsgErr::SenderMustBeDealer));
|
|
|
|
// change the header
|
|
let header = create_valid_header(setup.dealer, setup.aggregator);
|
|
|
|
let message = Message {
|
|
header,
|
|
payload: valid_payload,
|
|
};
|
|
|
|
let validate_message = Validate::validate(&message);
|
|
assert_eq!(validate_message, Err(MsgErr::ReceiverMustBeSigner));
|
|
|
|
let participants = vec![setup.signer1];
|
|
shares.truncate(1);
|
|
let mut share_commitment = generate_share_commitment(&shares, participants);
|
|
|
|
// change the payload to have only 1 commitment
|
|
let payload = Payload::SharePackage(SharePackage {
|
|
group_public,
|
|
secret_share: secret_share,
|
|
share_commitment: share_commitment.clone(),
|
|
});
|
|
let validate_payload = Validate::validate(&payload);
|
|
assert_eq!(
|
|
validate_payload,
|
|
Err(MsgErr::NotEnoughCommitments(constants::MIN_SIGNERS))
|
|
);
|
|
|
|
// build and use too many commitments
|
|
for i in 2..constants::MAX_SIGNERS as u64 + 2 {
|
|
share_commitment.insert(
|
|
ParticipantId::Signer(i),
|
|
share_commitment.clone()[&setup.signer1],
|
|
);
|
|
}
|
|
let payload = Payload::SharePackage(SharePackage {
|
|
group_public,
|
|
secret_share,
|
|
share_commitment,
|
|
});
|
|
let validate_payload = Validate::validate(&payload);
|
|
assert_eq!(validate_payload, Err(MsgErr::TooManyCommitments));
|
|
}
|
|
|
|
#[test]
|
|
fn serialize_sharepackage() {
|
|
let setup = basic_setup();
|
|
|
|
let (mut shares, _pubkeys) =
|
|
frost::keygen_with_dealer(setup.num_signers, setup.threshold, setup.rng.clone()).unwrap();
|
|
|
|
let header = create_valid_header(setup.dealer, setup.signer1);
|
|
|
|
let group_public = VerificationKey::from(
|
|
verification_key::VerificationKey::try_from(shares[0].group_public.bytes).unwrap(),
|
|
);
|
|
let secret_share = Secret(shares[0].share.value.0.to_bytes());
|
|
|
|
let participants = vec![setup.signer1];
|
|
shares.truncate(1);
|
|
let share_commitment = generate_share_commitment(&shares, participants);
|
|
|
|
let payload = Payload::SharePackage(SharePackage {
|
|
group_public,
|
|
secret_share,
|
|
share_commitment: share_commitment.clone(),
|
|
});
|
|
|
|
let message = Message {
|
|
header: header,
|
|
payload: payload.clone(),
|
|
};
|
|
|
|
// check general structure and header serialization/deserialization
|
|
serialize_message(message, setup.dealer, setup.signer1);
|
|
|
|
// check payload serialization/deserialization
|
|
let mut payload_serialized_bytes = bincode::serialize(&payload).unwrap();
|
|
// check the message type is correct
|
|
let deserialized_msg_type: MsgType =
|
|
bincode::deserialize(&payload_serialized_bytes[0..4]).unwrap();
|
|
assert_eq!(deserialized_msg_type, MsgType::SharePackage);
|
|
|
|
// remove the msg_type from the the payload
|
|
payload_serialized_bytes =
|
|
(&payload_serialized_bytes[4..payload_serialized_bytes.len()]).to_vec();
|
|
|
|
// group_public is 32 bytes
|
|
let deserialized_group_public: VerificationKey =
|
|
bincode::deserialize(&payload_serialized_bytes[0..32]).unwrap();
|
|
// secret share is 32 bytes
|
|
let deserialized_secret_share: Secret =
|
|
bincode::deserialize(&payload_serialized_bytes[32..64]).unwrap();
|
|
// rest of the message is the map: 32(Commitment) + 8(ParticipantId) + 8(map.len())
|
|
let deserialized_share_commitment: BTreeMap<ParticipantId, Commitment> =
|
|
bincode::deserialize(&payload_serialized_bytes[64..112]).unwrap();
|
|
|
|
// check the map len
|
|
let deserialized_map_len: u64 =
|
|
bincode::deserialize(&payload_serialized_bytes[64..72]).unwrap();
|
|
assert_eq!(deserialized_map_len, 1);
|
|
|
|
// no leftover bytes
|
|
assert_eq!(payload_serialized_bytes.len(), 112);
|
|
|
|
assert_eq!(deserialized_group_public, group_public);
|
|
assert_eq!(deserialized_secret_share, secret_share);
|
|
assert_eq!(deserialized_share_commitment, share_commitment);
|
|
}
|
|
|
|
#[test]
|
|
fn validate_signingcommitments() {
|
|
let mut setup = basic_setup();
|
|
|
|
let (_nonce, commitment) = frost::preprocess(1, u64::from(setup.signer1), &mut setup.rng);
|
|
|
|
let header = create_valid_header(setup.aggregator, setup.signer2);
|
|
|
|
let payload = Payload::SigningCommitments(SigningCommitments {
|
|
hiding: Commitment(jubjub::AffinePoint::from(commitment[0].hiding).to_bytes()),
|
|
binding: Commitment(jubjub::AffinePoint::from(commitment[0].binding).to_bytes()),
|
|
});
|
|
|
|
let message = Message {
|
|
header,
|
|
payload: payload.clone(),
|
|
};
|
|
|
|
let validate_message = Validate::validate(&message);
|
|
assert_eq!(validate_message, Err(MsgErr::SenderMustBeSigner));
|
|
|
|
// change the header
|
|
let header = create_valid_header(setup.signer1, setup.signer2);
|
|
|
|
let message = Message {
|
|
header,
|
|
payload: payload.clone(),
|
|
};
|
|
|
|
let validate_message = Validate::validate(&message);
|
|
assert_eq!(validate_message, Err(MsgErr::ReceiverMustBeAggregator));
|
|
|
|
// change the header to be valid
|
|
let header = create_valid_header(setup.signer1, setup.aggregator);
|
|
|
|
let validate_message = Validate::validate(&Message { header, payload }).err();
|
|
|
|
assert_eq!(validate_message, None);
|
|
}
|
|
|
|
#[test]
|
|
fn serialize_signingcommitments() {
|
|
let mut setup = basic_setup();
|
|
|
|
let (_nonce, commitment) = frost::preprocess(1, u64::from(setup.signer1), &mut setup.rng);
|
|
|
|
let header = create_valid_header(setup.aggregator, setup.signer1);
|
|
|
|
let hiding = Commitment(jubjub::AffinePoint::from(commitment[0].hiding).to_bytes());
|
|
let binding = Commitment(jubjub::AffinePoint::from(commitment[0].binding).to_bytes());
|
|
|
|
let payload = Payload::SigningCommitments(SigningCommitments { hiding, binding });
|
|
|
|
let message = Message {
|
|
header: header,
|
|
payload: payload.clone(),
|
|
};
|
|
|
|
// check general structure serialization/deserialization
|
|
serialize_message(message, setup.aggregator, setup.signer1);
|
|
|
|
// check payload serialization/deserialization
|
|
let mut payload_serialized_bytes = bincode::serialize(&payload).unwrap();
|
|
// check the message type is correct
|
|
let deserialized_msg_type: MsgType =
|
|
bincode::deserialize(&payload_serialized_bytes[0..4]).unwrap();
|
|
assert_eq!(deserialized_msg_type, MsgType::SigningCommitments);
|
|
|
|
// remove the msg_type from the the payload
|
|
payload_serialized_bytes =
|
|
(&payload_serialized_bytes[4..payload_serialized_bytes.len()]).to_vec();
|
|
|
|
// hiding is 32 bytes
|
|
let deserialized_hiding: Commitment =
|
|
bincode::deserialize(&payload_serialized_bytes[0..32]).unwrap();
|
|
// binding is 43 bytes kore
|
|
let deserialized_binding: Commitment =
|
|
bincode::deserialize(&payload_serialized_bytes[32..64]).unwrap();
|
|
|
|
// no leftover bytes
|
|
assert_eq!(payload_serialized_bytes.len(), 64);
|
|
|
|
assert_eq!(deserialized_hiding, hiding);
|
|
assert_eq!(deserialized_binding, binding);
|
|
}
|
|
|
|
#[test]
|
|
fn validate_signingpackage() {
|
|
let mut setup = basic_setup();
|
|
|
|
let (_nonce, commitment1) = frost::preprocess(1, u64::from(setup.signer1), &mut setup.rng);
|
|
let (_nonce, commitment2) = frost::preprocess(1, u64::from(setup.signer2), &mut setup.rng);
|
|
|
|
let header = create_valid_header(setup.signer1, setup.signer2);
|
|
|
|
// try with only 1 commitment
|
|
let commitments = vec![commitment1[0]];
|
|
let participants = vec![setup.signer1];
|
|
let signing_commitments = create_signing_commitments(commitments, participants);
|
|
|
|
let payload = Payload::SigningPackage(SigningPackage {
|
|
signing_commitments: signing_commitments.clone(),
|
|
message: "hola".as_bytes().to_vec(),
|
|
});
|
|
let validate_payload = Validate::validate(&payload);
|
|
assert_eq!(
|
|
validate_payload,
|
|
Err(MsgErr::NotEnoughCommitments(constants::MIN_SIGNERS))
|
|
);
|
|
|
|
// add too many commitments
|
|
let mut big_signing_commitments = BTreeMap::<ParticipantId, SigningCommitments>::new();
|
|
for i in 0..constants::MAX_SIGNERS as u64 + 1 {
|
|
big_signing_commitments.insert(
|
|
ParticipantId::Signer(i),
|
|
signing_commitments[&setup.signer1].clone(),
|
|
);
|
|
}
|
|
let payload = Payload::SigningPackage(SigningPackage {
|
|
signing_commitments: big_signing_commitments,
|
|
message: "hola".as_bytes().to_vec(),
|
|
});
|
|
let validate_payload = Validate::validate(&payload);
|
|
assert_eq!(validate_payload, Err(MsgErr::TooManyCommitments));
|
|
|
|
// change to 2 commitments
|
|
let commitments = vec![commitment1[0], commitment2[0]];
|
|
let participants = vec![setup.signer1, setup.signer2];
|
|
let signing_commitments = create_signing_commitments(commitments, participants);
|
|
|
|
let big_message = [0u8; constants::ZCASH_MAX_PROTOCOL_MESSAGE_LEN + 1].to_vec();
|
|
let payload = Payload::SigningPackage(SigningPackage {
|
|
signing_commitments: signing_commitments.clone(),
|
|
message: big_message,
|
|
});
|
|
let validate_payload = Validate::validate(&payload);
|
|
assert_eq!(validate_payload, Err(MsgErr::MsgTooBig));
|
|
|
|
let message = Message {
|
|
header,
|
|
payload: payload.clone(),
|
|
};
|
|
let validate_message = Validate::validate(&message);
|
|
assert_eq!(validate_message, Err(MsgErr::SenderMustBeAggregator));
|
|
|
|
// change header
|
|
let header = create_valid_header(setup.aggregator, setup.dealer);
|
|
|
|
let message = Message {
|
|
header: header,
|
|
payload: payload.clone(),
|
|
};
|
|
|
|
let validate_message = Validate::validate(&message);
|
|
assert_eq!(validate_message, Err(MsgErr::ReceiverMustBeSigner));
|
|
|
|
let header = create_valid_header(setup.aggregator, setup.signer1);
|
|
let payload = Payload::SigningPackage(SigningPackage {
|
|
signing_commitments,
|
|
message: "hola".as_bytes().to_vec(),
|
|
});
|
|
|
|
let validate_message = Validate::validate(&Message { header, payload }).err();
|
|
assert_eq!(validate_message, None);
|
|
}
|
|
|
|
#[test]
|
|
fn serialize_signingpackage() {
|
|
let mut setup = basic_setup();
|
|
|
|
let (_nonce, commitment1) = frost::preprocess(1, u64::from(setup.signer1), &mut setup.rng);
|
|
let (_nonce, commitment2) = frost::preprocess(1, u64::from(setup.signer2), &mut setup.rng);
|
|
|
|
let header = create_valid_header(setup.aggregator, setup.signer1);
|
|
|
|
let commitments = vec![commitment1[0], commitment2[0]];
|
|
let participants = vec![setup.signer1, setup.signer2];
|
|
let signing_commitments = create_signing_commitments(commitments, participants);
|
|
|
|
let payload = Payload::SigningPackage(SigningPackage {
|
|
signing_commitments: signing_commitments.clone(),
|
|
message: "hola".as_bytes().to_vec(),
|
|
});
|
|
|
|
let message = Message {
|
|
header: header,
|
|
payload: payload.clone(),
|
|
};
|
|
|
|
// check general structure serialization/deserialization
|
|
serialize_message(message, setup.aggregator, setup.signer1);
|
|
|
|
// check payload serialization/deserialization
|
|
let mut payload_serialized_bytes = bincode::serialize(&payload).unwrap();
|
|
|
|
// check the message type is correct
|
|
let deserialized_msg_type: MsgType =
|
|
bincode::deserialize(&payload_serialized_bytes[0..4]).unwrap();
|
|
assert_eq!(deserialized_msg_type, MsgType::SigningPackage);
|
|
|
|
// remove the msg_type from the the payload
|
|
payload_serialized_bytes =
|
|
(&payload_serialized_bytes[4..payload_serialized_bytes.len()]).to_vec();
|
|
|
|
// check the map len
|
|
let deserialized_map_len: u64 = bincode::deserialize(&payload_serialized_bytes[0..8]).unwrap();
|
|
assert_eq!(deserialized_map_len, 2);
|
|
|
|
// Each SigningCommitment is 64 bytes and the ParticipantId is 8 bytes.
|
|
// This is multiplied by the map len, also include the map len bytes.
|
|
let deserialized_signing_commitments: BTreeMap<ParticipantId, SigningCommitments> =
|
|
bincode::deserialize(&payload_serialized_bytes[0..152]).unwrap();
|
|
|
|
// Message is from the end of the map up to the end of the message.
|
|
let deserialized_message: Vec<u8> =
|
|
bincode::deserialize(&payload_serialized_bytes[152..payload_serialized_bytes.len()])
|
|
.unwrap();
|
|
|
|
// no leftover bytes
|
|
assert_eq!(payload_serialized_bytes.len(), 164);
|
|
|
|
assert_eq!(deserialized_signing_commitments, signing_commitments);
|
|
assert_eq!(deserialized_message, "hola".as_bytes().to_vec());
|
|
}
|
|
|
|
#[test]
|
|
fn validate_signatureshare() {
|
|
let mut setup = basic_setup();
|
|
|
|
// signers and aggregator should have this data from `SharePackage`
|
|
let (shares, _pubkeys) =
|
|
frost::keygen_with_dealer(setup.num_signers, setup.threshold, setup.rng.clone()).unwrap();
|
|
|
|
// create a signing package, this is done in the aggregator side.
|
|
// the signrs should have this data from `SigningPackage`
|
|
let (nonce1, commitment1) = frost::preprocess(1, u64::from(setup.signer1), &mut setup.rng);
|
|
let (_nonce2, commitment2) = frost::preprocess(1, u64::from(setup.signer2), &mut setup.rng);
|
|
let commitments = vec![commitment1[0], commitment2[0]];
|
|
let participants = vec![setup.signer1, setup.signer2];
|
|
let signing_commitments = create_signing_commitments(commitments, participants);
|
|
|
|
let signing_package = frost::SigningPackage::from(SigningPackage {
|
|
signing_commitments: signing_commitments.clone(),
|
|
message: "hola".as_bytes().to_vec(),
|
|
});
|
|
|
|
// here we get started with the `SignatureShare` message.
|
|
let signature_share = frost::sign(&signing_package, nonce1[0], &shares[0]).unwrap();
|
|
|
|
// this header is invalid
|
|
let header = create_valid_header(setup.aggregator, setup.signer1);
|
|
|
|
let payload = Payload::SignatureShare(SignatureShare {
|
|
signature: SignatureResponse(signature_share.signature.0.to_bytes()),
|
|
});
|
|
|
|
let message = Message {
|
|
header,
|
|
payload: payload.clone(),
|
|
};
|
|
|
|
let validate_message = Validate::validate(&message);
|
|
assert_eq!(validate_message, Err(MsgErr::SenderMustBeSigner));
|
|
|
|
// change the header, still invalid.
|
|
let header = create_valid_header(setup.signer1, setup.signer2);
|
|
|
|
let message = Message {
|
|
header,
|
|
payload: payload.clone(),
|
|
};
|
|
|
|
let validate_message = Validate::validate(&message);
|
|
assert_eq!(validate_message, Err(MsgErr::ReceiverMustBeAggregator));
|
|
|
|
// change the header to be valid
|
|
let header = create_valid_header(setup.signer1, setup.aggregator);
|
|
|
|
let validate_message = Validate::validate(&Message { header, payload }).err();
|
|
|
|
assert_eq!(validate_message, None);
|
|
}
|
|
|
|
#[test]
|
|
fn serialize_signatureshare() {
|
|
let mut setup = basic_setup();
|
|
|
|
// signers and aggregator should have this data from `SharePackage`
|
|
let (shares, _pubkeys) =
|
|
frost::keygen_with_dealer(setup.num_signers, setup.threshold, setup.rng.clone()).unwrap();
|
|
|
|
// create a signing package, this is done in the aggregator side.
|
|
// the signers should have this data from `SigningPackage`
|
|
let (nonce1, commitment1) = frost::preprocess(1, u64::from(setup.signer1), &mut setup.rng);
|
|
let (_nonce2, commitment2) = frost::preprocess(1, u64::from(setup.signer2), &mut setup.rng);
|
|
let commitments = vec![commitment1[0], commitment2[0]];
|
|
let participants = vec![setup.signer1, setup.signer2];
|
|
let signing_commitments = create_signing_commitments(commitments, participants);
|
|
|
|
let signing_package = frost::SigningPackage::from(SigningPackage {
|
|
signing_commitments: signing_commitments.clone(),
|
|
message: "hola".as_bytes().to_vec(),
|
|
});
|
|
|
|
// here we get started with the `SignatureShare` message.
|
|
let signature_share = frost::sign(&signing_package, nonce1[0], &shares[0]).unwrap();
|
|
|
|
// valid header
|
|
let header = create_valid_header(setup.signer1, setup.aggregator);
|
|
|
|
let signature = SignatureResponse(signature_share.signature.0.to_bytes());
|
|
let payload = Payload::SignatureShare(SignatureShare { signature });
|
|
|
|
let message = Message {
|
|
header: header,
|
|
payload: payload.clone(),
|
|
};
|
|
|
|
// check general structure serialization/deserialization
|
|
serialize_message(message, setup.signer1, setup.aggregator);
|
|
|
|
// check payload serialization/deserialization
|
|
let mut payload_serialized_bytes = bincode::serialize(&payload).unwrap();
|
|
|
|
// check the message type is correct
|
|
let deserialized_msg_type: MsgType =
|
|
bincode::deserialize(&payload_serialized_bytes[0..4]).unwrap();
|
|
assert_eq!(deserialized_msg_type, MsgType::SignatureShare);
|
|
|
|
// remove the msg_type from the the payload
|
|
payload_serialized_bytes =
|
|
(&payload_serialized_bytes[4..payload_serialized_bytes.len()]).to_vec();
|
|
|
|
// signature is 32 bytes
|
|
let deserialized_signature: SignatureResponse =
|
|
bincode::deserialize(&payload_serialized_bytes[0..32]).unwrap();
|
|
|
|
// no leftover bytes
|
|
assert_eq!(payload_serialized_bytes.len(), 32);
|
|
|
|
assert_eq!(deserialized_signature, signature);
|
|
}
|
|
|
|
#[test]
|
|
fn validate_aggregatesignature() {
|
|
let (setup, group_signature_res) = full_setup();
|
|
|
|
// this header is invalid
|
|
let header = create_valid_header(setup.signer1, setup.aggregator);
|
|
|
|
let payload = Payload::AggregateSignature(AggregateSignature {
|
|
group_commitment: GroupCommitment::from(group_signature_res),
|
|
schnorr_signature: SignatureResponse::from(group_signature_res),
|
|
});
|
|
|
|
let message = Message {
|
|
header,
|
|
payload: payload.clone(),
|
|
};
|
|
|
|
let validate_message = Validate::validate(&message);
|
|
assert_eq!(validate_message, Err(MsgErr::SenderMustBeAggregator));
|
|
|
|
// change the header, still invalid.
|
|
let header = create_valid_header(setup.aggregator, setup.dealer);
|
|
|
|
let message = Message {
|
|
header,
|
|
payload: payload.clone(),
|
|
};
|
|
|
|
let validate_message = Validate::validate(&message);
|
|
assert_eq!(validate_message, Err(MsgErr::ReceiverMustBeSigner));
|
|
|
|
// change the header to be valid
|
|
let header = create_valid_header(setup.aggregator, setup.signer1);
|
|
|
|
let validate_message = Validate::validate(&Message { header, payload }).err();
|
|
|
|
assert_eq!(validate_message, None);
|
|
}
|
|
|
|
#[test]
|
|
fn serialize_aggregatesignature() {
|
|
let (setup, group_signature_res) = full_setup();
|
|
|
|
let header = create_valid_header(setup.aggregator, setup.signer1);
|
|
|
|
let group_commitment = GroupCommitment::from(group_signature_res);
|
|
let schnorr_signature = SignatureResponse::from(group_signature_res);
|
|
let payload = Payload::AggregateSignature(AggregateSignature {
|
|
group_commitment,
|
|
schnorr_signature,
|
|
});
|
|
|
|
let message = Message {
|
|
header,
|
|
payload: payload.clone(),
|
|
};
|
|
|
|
// check general structure serialization/deserialization
|
|
serialize_message(message, setup.aggregator, setup.signer1);
|
|
|
|
// check payload serialization/deserialization
|
|
let mut payload_serialized_bytes = bincode::serialize(&payload).unwrap();
|
|
|
|
// check the message type is correct
|
|
let deserialized_msg_type: MsgType =
|
|
bincode::deserialize(&payload_serialized_bytes[0..4]).unwrap();
|
|
assert_eq!(deserialized_msg_type, MsgType::AggregateSignature);
|
|
|
|
// remove the msg_type from the the payload
|
|
payload_serialized_bytes =
|
|
(&payload_serialized_bytes[4..payload_serialized_bytes.len()]).to_vec();
|
|
|
|
// group_commitment is 32 bytes
|
|
let deserialized_group_commiment: GroupCommitment =
|
|
bincode::deserialize(&payload_serialized_bytes[0..32]).unwrap();
|
|
// schnorr_signature is 32 bytes
|
|
let deserialized_schnorr_signature: SignatureResponse =
|
|
bincode::deserialize(&payload_serialized_bytes[32..64]).unwrap();
|
|
|
|
// no leftover bytes
|
|
assert_eq!(payload_serialized_bytes.len(), 64);
|
|
|
|
assert_eq!(deserialized_group_commiment, group_commitment);
|
|
assert_eq!(deserialized_schnorr_signature, schnorr_signature);
|
|
}
|
|
|
|
#[test]
|
|
fn btreemap() {
|
|
let mut setup = basic_setup();
|
|
let mut map = BTreeMap::new();
|
|
|
|
let (_nonce, commitment) = frost::preprocess(1, u64::from(setup.signer1), &mut setup.rng);
|
|
|
|
let commitments = vec![commitment[0]];
|
|
let participants = vec![setup.signer1];
|
|
let signing_commitments = create_signing_commitments(commitments, participants);
|
|
|
|
map.insert(ParticipantId::Signer(1), &signing_commitments);
|
|
map.insert(ParticipantId::Signer(2), &signing_commitments);
|
|
map.insert(ParticipantId::Signer(0), &signing_commitments);
|
|
|
|
// Check the ascending order
|
|
let mut map_iter = map.iter();
|
|
let (key, _) = map_iter.next().unwrap();
|
|
assert_eq!(*key, ParticipantId::Signer(0));
|
|
let (key, _) = map_iter.next().unwrap();
|
|
assert_eq!(*key, ParticipantId::Signer(1));
|
|
let (key, _) = map_iter.next().unwrap();
|
|
assert_eq!(*key, ParticipantId::Signer(2));
|
|
|
|
// Add a repeated key
|
|
map.insert(ParticipantId::Signer(1), &signing_commitments);
|
|
// BTreeMap is not increasing
|
|
assert_eq!(map.len(), 3);
|
|
}
|
|
|
|
// utility functions
|
|
|
|
fn create_valid_header(sender: ParticipantId, receiver: ParticipantId) -> Header {
|
|
Validate::validate(&Header {
|
|
version: constants::BASIC_FROST_SERIALIZATION,
|
|
sender: sender,
|
|
receiver: receiver,
|
|
})
|
|
.expect("always a valid header")
|
|
.clone()
|
|
}
|
|
|
|
fn serialize_header(
|
|
header_serialized_bytes: Vec<u8>,
|
|
sender: ParticipantId,
|
|
receiver: ParticipantId,
|
|
) {
|
|
let deserialized_version: MsgVersion =
|
|
bincode::deserialize(&header_serialized_bytes[0..1]).unwrap();
|
|
let deserialized_sender: ParticipantId =
|
|
bincode::deserialize(&header_serialized_bytes[1..9]).unwrap();
|
|
let deserialized_receiver: ParticipantId =
|
|
bincode::deserialize(&header_serialized_bytes[9..17]).unwrap();
|
|
assert_eq!(deserialized_version, constants::BASIC_FROST_SERIALIZATION);
|
|
assert_eq!(deserialized_sender, sender);
|
|
assert_eq!(deserialized_receiver, receiver);
|
|
}
|
|
|
|
fn serialize_message(message: Message, sender: ParticipantId, receiver: ParticipantId) {
|
|
let serialized_bytes = bincode::serialize(&message).unwrap();
|
|
let deserialized_bytes: Message = bincode::deserialize(&serialized_bytes).unwrap();
|
|
assert_eq!(message, deserialized_bytes);
|
|
|
|
let serialized_json = serde_json::to_string(&message).unwrap();
|
|
let deserialized_json: Message = serde_json::from_str(serialized_json.as_str()).unwrap();
|
|
assert_eq!(message, deserialized_json);
|
|
|
|
let header_serialized_bytes = bincode::serialize(&message.header).unwrap();
|
|
serialize_header(header_serialized_bytes, sender, receiver);
|
|
|
|
// make sure the message fields are in the right order
|
|
let message_serialized_bytes = bincode::serialize(&message).unwrap();
|
|
let deserialized_header: Header =
|
|
bincode::deserialize(&message_serialized_bytes[0..17]).unwrap();
|
|
let deserialized_payload: Payload =
|
|
bincode::deserialize(&message_serialized_bytes[17..message_serialized_bytes.len()])
|
|
.unwrap();
|
|
assert_eq!(deserialized_header, message.header);
|
|
assert_eq!(deserialized_payload, message.payload);
|
|
}
|
|
|
|
struct Setup {
|
|
rng: rand::rngs::ThreadRng,
|
|
num_signers: u8,
|
|
threshold: u8,
|
|
dealer: ParticipantId,
|
|
aggregator: ParticipantId,
|
|
signer1: ParticipantId,
|
|
signer2: ParticipantId,
|
|
}
|
|
|
|
fn basic_setup() -> Setup {
|
|
Setup {
|
|
rng: thread_rng(),
|
|
num_signers: 3,
|
|
threshold: 2,
|
|
dealer: ParticipantId::Dealer,
|
|
aggregator: ParticipantId::Aggregator,
|
|
signer1: ParticipantId::Signer(0),
|
|
signer2: ParticipantId::Signer(1),
|
|
}
|
|
}
|
|
|
|
fn full_setup() -> (Setup, signature::Signature<SpendAuth>) {
|
|
let mut setup = basic_setup();
|
|
|
|
// aggregator creates the shares and pubkeys for this round
|
|
let (shares, pubkeys) =
|
|
frost::keygen_with_dealer(setup.num_signers, setup.threshold, setup.rng.clone()).unwrap();
|
|
|
|
let mut nonces: std::collections::HashMap<u64, Vec<frost::SigningNonces>> =
|
|
std::collections::HashMap::with_capacity(setup.threshold as usize);
|
|
let mut commitments: Vec<frost::SigningCommitments> =
|
|
Vec::with_capacity(setup.threshold as usize);
|
|
|
|
// aggregator generates nonces and signing commitments for each participant.
|
|
for participant_index in 1..(setup.threshold + 1) {
|
|
let (nonce, commitment) = frost::preprocess(1, participant_index as u64, &mut setup.rng);
|
|
nonces.insert(participant_index as u64, nonce);
|
|
commitments.push(commitment[0]);
|
|
}
|
|
|
|
// aggregator generates a signing package
|
|
let mut signature_shares: Vec<frost::SignatureShare> =
|
|
Vec::with_capacity(setup.threshold as usize);
|
|
let message = "message to sign".as_bytes().to_vec();
|
|
let signing_package = frost::SigningPackage {
|
|
message: message.clone(),
|
|
signing_commitments: commitments,
|
|
};
|
|
|
|
// each participant generates their signature share
|
|
for (participant_index, nonce) in nonces {
|
|
let share_package = shares
|
|
.iter()
|
|
.find(|share| participant_index == share.index)
|
|
.unwrap();
|
|
let nonce_to_use = nonce[0];
|
|
let signature_share = frost::sign(&signing_package, nonce_to_use, share_package).unwrap();
|
|
signature_shares.push(signature_share);
|
|
}
|
|
|
|
// aggregator generate the final signature
|
|
let final_signature =
|
|
frost::aggregate(&signing_package, &signature_shares[..], &pubkeys).unwrap();
|
|
(setup, final_signature)
|
|
}
|
|
|
|
fn generate_share_commitment(
|
|
shares: &Vec<frost::SharePackage>,
|
|
participants: Vec<ParticipantId>,
|
|
) -> BTreeMap<ParticipantId, Commitment> {
|
|
assert_eq!(shares.len(), participants.len());
|
|
participants
|
|
.into_iter()
|
|
.zip(shares)
|
|
.map(|(participant_id, share)| {
|
|
(
|
|
participant_id,
|
|
Commitment::from(share.share.commitment.0[0].clone()),
|
|
)
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
fn create_signing_commitments(
|
|
commitments: Vec<frost::SigningCommitments>,
|
|
participants: Vec<ParticipantId>,
|
|
) -> BTreeMap<ParticipantId, SigningCommitments> {
|
|
assert_eq!(commitments.len(), participants.len());
|
|
participants
|
|
.into_iter()
|
|
.zip(commitments)
|
|
.map(|(participant_id, commitment)| {
|
|
let signing_commitment = SigningCommitments {
|
|
hiding: Commitment(jubjub::AffinePoint::from(commitment.hiding).to_bytes()),
|
|
binding: Commitment(jubjub::AffinePoint::from(commitment.binding).to_bytes()),
|
|
};
|
|
(participant_id, signing_commitment)
|
|
})
|
|
.collect()
|
|
}
|