Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

inv-tshare: Threshold (re-)sharing protocol #542

Merged
merged 74 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
b0d074b
inv-tshare: Threshold (re-)sharing protocol
Jul 20, 2024
acbfc83
Include Lagrange
emmorais Aug 19, 2024
b1dee3d
Call Tshare once for sharing k
emmorais Aug 21, 2024
44a983c
Include tshare for chi
emmorais Aug 22, 2024
8008d7e
Add test for lagrange coefficient at zero, conversion works
emmorais Aug 30, 2024
2acd393
Create unit test to validate auxinfo ids
emmorais Aug 30, 2024
edca2a2
Unit test for checking auxinfo id consistency
emmorais Aug 30, 2024
37f88fe
Conver test cases for the input
emmorais Aug 30, 2024
a7d6aef
Check constant terms consistency
emmorais Aug 30, 2024
3b038d5
Check constant terms
emmorais Aug 30, 2024
9f32b5f
Check the share is consistent
emmorais Aug 30, 2024
9de4431
Fmt
emmorais Sep 3, 2024
798ecca
Warnings and clippy
emmorais Sep 3, 2024
4a691a8
Public key checks
emmorais Sep 6, 2024
0a95528
Include unit test for lagrange at zero
emmorais Sep 6, 2024
b680b94
Fmt, clippy and warnings
emmorais Sep 6, 2024
609a91e
More warnings
emmorais Sep 6, 2024
ee4ea23
Merge branch 'main' into inv-tshare
emmorais Sep 6, 2024
1924882
Clippy
emmorais Sep 6, 2024
7a47396
Documentation
emmorais Sep 6, 2024
a90c0d4
Fix the public key validation
emmorais Sep 8, 2024
830dafd
Fix saved public key values, protocol working
emmorais Sep 8, 2024
bcd66f9
Use participant_coordinate instead of incrementing the index
emmorais Sep 10, 2024
272d067
Fmt
emmorais Sep 10, 2024
89d77c0
Remove unused module
emmorais Sep 10, 2024
64bef43
Testing cases for the full protocol
emmorais Sep 12, 2024
8068f07
Full protocol test for 2/3 threshold sharing
emmorais Sep 13, 2024
516dae2
Negative test cases
emmorais Sep 13, 2024
edb525d
Refactor the t-out-of-t sub-protocol
emmorais Sep 13, 2024
4e213bd
Remove unused code
emmorais Sep 13, 2024
b68c071
More adjustments
emmorais Sep 13, 2024
6dbc750
Introduce dedicated type for evaluations
emmorais Sep 13, 2024
b478441
Remove old TODOs
emmorais Sep 13, 2024
0207eac
Remove unneeded variable
emmorais Sep 16, 2024
eeb06eb
Use Scalar instead of BigInt
emmorais Sep 16, 2024
80f605a
Remove old TODOs
emmorais Sep 16, 2024
b4b948e
Minor adjustments
emmorais Sep 16, 2024
ae88cb1
Remove unneeded operation in share.rs
emmorais Oct 4, 2024
767ca09
Remove unnecessary clone derivation
emmorais Oct 4, 2024
d855355
Remove unnecessary validations
emmorais Oct 4, 2024
ce0977d
Update old comment
emmorais Oct 7, 2024
6fa035f
Add new comment
emmorais Oct 7, 2024
560683c
Update comment
emmorais Oct 7, 2024
b432f0e
Replace Schnorr proofs for all coefficients by a single proof for the…
emmorais Oct 7, 2024
9f70a3d
Fmt
emmorais Oct 7, 2024
679e9c9
Fmt
emmorais Oct 7, 2024
8410c77
Remove public_share from commitment
emmorais Oct 8, 2024
6715a9a
Move encryption of shares one round earlier
emmorais Oct 9, 2024
abf946c
Continue moving encrypted shares to second round
emmorais Oct 9, 2024
7e3b0ac
Renaming variables
emmorais Oct 9, 2024
c578fc9
Remove commented code
emmorais Oct 9, 2024
6550a2b
Minor adjustments
emmorais Oct 9, 2024
fa1c8c5
Add chain_code to keygen output
emmorais Sep 23, 2024
703bc57
Add shift to signature generation
emmorais Sep 25, 2024
1d3a030
Improve error message
emmorais Sep 25, 2024
22496d2
Refactor expect expression
emmorais Sep 25, 2024
37c8ebe
Refactor repeated code
emmorais Sep 25, 2024
387dae7
Refactor the hash calculation
emmorais Sep 25, 2024
1afb305
Distributed chain code finished and included in the transcript
emmorais Sep 26, 2024
81dfbd4
Remove unnecessary copyright
emmorais Sep 26, 2024
0160e10
If CKD fails, try again with incremented counter
emmorais Sep 26, 2024
4cd32aa
Introduce auxiliary macro to xor 256 bits
emmorais Sep 27, 2024
29cd712
Replace keccak by hmac512
emmorais Sep 29, 2024
ce5541e
Introduce first unit test from test vectors
emmorais Sep 30, 2024
8357a0a
Child derivation key unit test from test vectors
emmorais Oct 1, 2024
d9576c6
Clippy
emmorais Oct 1, 2024
0825068
Use CKDOutput instead of tuple
emmorais Oct 2, 2024
3946c17
Retry master key generation on failure
emmorais Oct 9, 2024
aaa33ad
Merge branch 'main' into inv-tshare
emmorais Oct 10, 2024
e5102ab
Fmt
emmorais Oct 10, 2024
ab5a265
Typo
emmorais Oct 10, 2024
f1cdc3e
n=2 working, but n=3 not
emmorais Oct 14, 2024
1389fe7
Minor adjustments
emmorais Oct 15, 2024
f42dbdc
Create maybe_finish_round2
emmorais Oct 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/threaded_example/threaded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ impl Worker {
let record = self.presign_records.take(&key_id);

let threshold = key_shares.len();
let inputs = sign::Input::new(b"hello world", record, key_shares.to_vec(), threshold);
let inputs = sign::Input::new(b"hello world", record, key_shares.to_vec(), threshold, None);
self.new_sub_protocol::<SignParticipant>(sid, inputs, key_id)
}
}
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ pub mod presign;
mod protocol;
mod ring_pedersen;
pub mod sign;
pub mod slip0010;
pub mod tshare;
mod utils;
mod zkp;
Expand Down
6 changes: 3 additions & 3 deletions src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,11 @@ pub enum TshareMessageType {
R1CommitHash,
/// The information committed to in Round 1
R2Decommit,
/// The encrypted private share from a participant to another.
R2PrivateShare,
/// A proof of knowledge of the discrete log of the value decommitted in
/// Round 2
R3Proofs,
/// The encrypted private share from a participant to another.
R3PrivateShare,
R3Proof,
}

/// An enum consisting of all keyrefresh message types
Expand Down
2 changes: 1 addition & 1 deletion src/presign/record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ pub(crate) struct RecordPair {
/// d_A)`, which is exactly a valid (normal) ECDSA signature.
///
/// [^cite]: [Wikipedia](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm#Signature_generation_algorithm)
#[derive(Clone, Zeroize, ZeroizeOnDrop, PartialEq, Eq)]
#[derive(Zeroize, ZeroizeOnDrop, PartialEq, Eq)]
pub struct PresignRecord {
R: CurvePoint,
k: Scalar,
Expand Down
51 changes: 36 additions & 15 deletions src/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -643,10 +643,12 @@ mod tests {
participant::Status,
presign,
sign::{self, InteractiveSignParticipant, SignParticipant},
slip0010,
tshare::{self, CoeffPrivate, TshareParticipant},
utils::{bn_to_scalar, testing::init_testing},
PresignParticipant,
};
use core::panic;
use k256::{ecdsa::signature::DigestVerifier, Scalar};
use rand::seq::IteratorRandom;
use sha3::{Digest, Keccak256};
Expand Down Expand Up @@ -846,38 +848,45 @@ mod tests {
#[ignore]
#[test]
fn test_full_protocol_execution_with_noninteractive_signing_works_larger_values() {
assert!(full_protocol_execution_with_noninteractive_signing_works(5, 5, 5).is_ok());
assert!(full_protocol_execution_with_noninteractive_signing_works(5, 4, 5).is_ok());
assert!(full_protocol_execution_with_noninteractive_signing_works(4, 4, 5).is_ok());
assert!(full_protocol_execution_with_noninteractive_signing_works(5, 3, 5).is_ok());
assert!(full_protocol_execution_with_noninteractive_signing_works(4, 3, 5).is_ok());
assert!(full_protocol_execution_with_noninteractive_signing_works(3, 3, 5).is_ok());
assert!(full_protocol_execution_with_noninteractive_signing_works(5, 5, 5, 42).is_ok());
assert!(full_protocol_execution_with_noninteractive_signing_works(5, 4, 5, 42).is_ok());
assert!(full_protocol_execution_with_noninteractive_signing_works(4, 4, 5, 42).is_ok());
assert!(full_protocol_execution_with_noninteractive_signing_works(5, 3, 5, 42).is_ok());
assert!(full_protocol_execution_with_noninteractive_signing_works(4, 3, 5, 42).is_ok());
assert!(full_protocol_execution_with_noninteractive_signing_works(3, 3, 5, 42).is_ok());
}

#[cfg_attr(feature = "flame_it", flame)]
#[test]
fn test_full_protocol_execution_with_noninteractive_signing_works() {
assert!(full_protocol_execution_with_noninteractive_signing_works(3, 3, 3).is_ok());
assert!(full_protocol_execution_with_noninteractive_signing_works(3, 2, 3).is_ok());
assert!(full_protocol_execution_with_noninteractive_signing_works(2, 2, 3).is_ok());
assert!(full_protocol_execution_with_noninteractive_signing_works(3, 3, 3, 42).is_ok());
assert!(full_protocol_execution_with_noninteractive_signing_works(3, 2, 3, 42).is_ok());
assert!(full_protocol_execution_with_noninteractive_signing_works(2, 2, 3, 42).is_ok());
// 2**31
let invalid_index = 1 << 31;
assert!(
full_protocol_execution_with_noninteractive_signing_works(3, 3, 3, invalid_index)
.is_err()
);
}

#[ignore]
#[test]
fn test_full_protocol_execution_with_noninteractive_signing_works_err_larger_values() {
assert!(full_protocol_execution_with_noninteractive_signing_works(3, 4, 5).is_err());
assert!(full_protocol_execution_with_noninteractive_signing_works(2, 4, 5).is_err());
assert!(full_protocol_execution_with_noninteractive_signing_works(3, 4, 5, 42).is_err());
assert!(full_protocol_execution_with_noninteractive_signing_works(2, 4, 5, 42).is_err());
}

#[test]
fn test_full_protocol_execution_with_noninteractive_signing_works_err() {
assert!(full_protocol_execution_with_noninteractive_signing_works(2, 3, 4).is_err());
assert!(full_protocol_execution_with_noninteractive_signing_works(2, 3, 4, 42).is_err());
}

fn full_protocol_execution_with_noninteractive_signing_works(
r: usize,
t: usize,
n: usize,
child_index: u32,
) -> Result<()> {
let mut rng = init_testing();
let QUORUM_REAL = r; // The real quorum size, which is the number of participants that will actually
Expand Down Expand Up @@ -1055,11 +1064,13 @@ mod tests {
let all_participants = configs.first().unwrap().all_participants();

// t-out-of-t conversion
let chain_code = keygen_outputs[&configs[0].id()].chain_code();
let rid = keygen_outputs[&configs[0].id()].rid();
let (mut toft_keygen_outputs, toft_public_keys) =
let (mut toft_keygen_outputs, _toft_public_keys) =
TshareParticipant::convert_to_t_out_of_t_shares(
tshare_outputs,
all_participants.clone(),
*chain_code,
*rid,
)?;

Expand All @@ -1083,6 +1094,11 @@ mod tests {
);
}

let public_key_shares = toft_keygen_outputs
.get(&configs.first().unwrap().id())
.unwrap()
.public_key_shares()
.to_vec();
let saved_public_key = toft_keygen_outputs
.get(&configs.first().unwrap().id())
.unwrap()
Expand Down Expand Up @@ -1189,8 +1205,13 @@ mod tests {
.into_iter()
.map(|config| {
let record = presign_outputs.remove(&config.id()).unwrap();
let input =
sign::Input::new(message, record, toft_public_keys.clone(), QUORUM_THRESHOLD);
let input = sign::Input::new(
message,
record,
public_key_shares.clone(),
QUORUM_THRESHOLD,
Some(shift_scalar),
);
Participant::<SignParticipant>::from_config(config, sign_sid, input)
})
.collect::<Result<Vec<_>>>()?;
Expand Down
2 changes: 1 addition & 1 deletion src/sign/interactive_sign/participant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ impl SigningMaterial {
// the same as the public keys size
let threshold = public_keys.len();
let signing_input =
sign::Input::new_from_digest(*digest, record, public_keys, threshold);
sign::Input::new_from_digest(*digest, record, public_keys, threshold, None);
// Note: this shouldn't throw an error because the only failure case should have
// also been checked by the presign constructor, and computation
// halted far before we reach this point.
Expand Down
7 changes: 7 additions & 0 deletions src/sign/non_interactive_sign/participant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ pub struct Input {
presign_record: PresignRecord,
public_key_shares: Vec<KeySharePublic>,
threshold: usize,
shift: Option<Scalar>,
}

impl Input {
Expand All @@ -92,12 +93,14 @@ impl Input {
record: PresignRecord,
public_key_shares: Vec<KeySharePublic>,
threshold: usize,
shift: Option<Scalar>,
) -> Self {
Self {
digest: Keccak256::new_with_prefix(message),
presign_record: record,
public_key_shares,
threshold,
shift,
}
}

Expand All @@ -110,12 +113,14 @@ impl Input {
record: PresignRecord,
public_key_shares: Vec<KeySharePublic>,
threshold: usize,
shift: Option<Scalar>,
) -> Self {
Self {
digest,
presign_record: record,
public_key_shares,
threshold,
shift,
}
}

Expand Down Expand Up @@ -597,6 +602,7 @@ mod test {
record,
keygen.public_key_shares().to_vec(),
quorum_size,
None,
)
});
let mut quorum = std::iter::zip(configs, inputs)
Expand Down Expand Up @@ -719,6 +725,7 @@ mod test {
presign_record,
keygen_output.public_key_shares().to_vec(),
threshold,
None,
);

let participant = SignParticipant::new(sid, id, other_participant_ids, input);
Expand Down
14 changes: 0 additions & 14 deletions src/sign/non_interactive_sign/share.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,3 @@ impl std::ops::Add<SignatureShare> for Scalar {
self + rhs.0
}
}

impl std::ops::Mul<SignatureShare> for SignatureShare {
type Output = Scalar;
fn mul(self, rhs: SignatureShare) -> Self::Output {
self.0 * rhs.0
}
}

impl std::ops::Mul<SignatureShare> for Scalar {
type Output = Scalar;
fn mul(self, rhs: SignatureShare) -> Self::Output {
self * rhs.0
}
}
31 changes: 7 additions & 24 deletions src/tshare/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub(crate) struct TshareDecommit {
u_i: [u8; 32], // The blinding factor is never read but it is included in the commitment.
pub rid: [u8; 32],
pub coeff_publics: Vec<CoeffPublic>,
pub As: Vec<CurvePoint>,
pub precom: CurvePoint,
}

impl TshareDecommit {
Expand All @@ -48,8 +48,8 @@ impl TshareDecommit {
rng: &mut R,
sid: &Identifier,
sender: &ParticipantIdentifier,
coeff_publics: Vec<CoeffPublic>,
sch_precoms: Vec<CurvePoint>,
coeff_publics: &[CoeffPublic],
sch_precom: CurvePoint,
) -> Self {
let mut rid = [0u8; 32];
let mut u_i = [0u8; 32];
Expand All @@ -60,20 +60,16 @@ impl TshareDecommit {
sender: *sender,
rid,
u_i,
coeff_publics,
As: sch_precoms,
coeff_publics: coeff_publics.to_vec(),
precom: sch_precom,
}
}

/// Deserialize a TshareDecommit from a message and verify it.
pub(crate) fn from_message(
message: &Message,
com: &TshareCommit,
threshold: usize,
) -> Result<Self> {
pub(crate) fn from_message(message: &Message, com: &TshareCommit) -> Result<Self> {
message.check_type(MessageType::Tshare(TshareMessageType::R2Decommit))?;
let tshare_decommit: TshareDecommit = deserialize!(&message.unverified_bytes)?;
tshare_decommit.verify(message.id(), message.from(), com, threshold)?;
tshare_decommit.verify(message.id(), message.from(), com)?;
Ok(tshare_decommit)
}

Expand All @@ -92,7 +88,6 @@ impl TshareDecommit {
sid: Identifier,
sender: ParticipantIdentifier,
com: &TshareCommit,
threshold: usize,
) -> Result<()> {
// Check the commitment.
let rebuilt_com = self.commit()?;
Expand All @@ -111,18 +106,6 @@ impl TshareDecommit {
return Err(InternalError::ProtocolError(Some(sender)));
}

// Check the number of commitments As.
if self.As.len() < threshold {
error!("Incorrect number of As");
return Err(InternalError::ProtocolError(Some(sender)));
}

// Check the set of coefficients.
if self.coeff_publics.len() < threshold {
error!("Incorrect number of public shares");
return Err(InternalError::ProtocolError(Some(sender)));
}

Ok(())
}
}
Expand Down
5 changes: 2 additions & 3 deletions src/tshare/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,8 @@ impl Output {
/// should not try to form public and private key shares independently.
///
/// The provided components must satisfy the following properties:
/// - Validity of private key share can be checked using Feldman's VSS,
/// but since the id is not known, it must be tested by the caller
/// - The public key shares must be from a unique set of participants
/// - Validity of private key share can be checked using Feldman's VSS.
/// - The public key shares must be from a unique set of participants.
pub fn from_parts(
public_coeffs: Vec<CoeffPublic>,
public_keys: Vec<KeySharePublic>,
Expand Down
Loading
Loading