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

One Round DKG #589

Merged
merged 58 commits into from
Aug 16, 2024
Merged
Changes from 1 commit
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
dcc26ec
Upstream GBP, divisor, circuit abstraction, and EC gadgets from FCMP++
kayabaNerve Jul 22, 2024
db31809
Initial eVRF implementation
kayabaNerve Jul 22, 2024
49a1831
Add the openings of the PCs to the eVRF as necessary
kayabaNerve Jul 22, 2024
772d033
Add implementation of secq256k1
kayabaNerve Jul 22, 2024
b847296
Make DKG Encryption a bit more flexible
kayabaNerve Jul 23, 2024
b6e6880
Make NUM_BITS an argument for the field macro
kayabaNerve Jul 23, 2024
b710303
Have the eVRF take a Zeroizing private key
kayabaNerve Jul 23, 2024
7710da4
Initial eVRF-based DKG
kayabaNerve Jul 24, 2024
fa31f26
Add embedwards25519 curve
kayabaNerve Jul 24, 2024
96175e1
Inline the eVRF into the DKG library
kayabaNerve Jul 25, 2024
05c26d7
Add documentation to the eVRF-based DKG
kayabaNerve Jul 25, 2024
eca82f3
Add paragraph claiming robustness
kayabaNerve Jul 25, 2024
00dc308
Update to the new eVRF proof
kayabaNerve Jul 25, 2024
ef68885
Finish routing the eVRF functionality
kayabaNerve Jul 25, 2024
4bd0d71
Add initial eVRF DKG test
kayabaNerve Jul 27, 2024
31ac0ac
Improve eVRF DKG
kayabaNerve Jul 28, 2024
c960d6b
Start using a proper error for the eVRF DKG
kayabaNerve Jul 28, 2024
f93bd42
Resolve various TODOs
kayabaNerve Jul 28, 2024
681010f
Ban zero ECDH keys, document non-zero requirements
kayabaNerve Jul 28, 2024
a6775d7
Implement eVRF traits, all the way up to the DKG, for secp256k1/ed25519
kayabaNerve Jul 28, 2024
c5cc0dc
Add Ristretto eVRF trait impls
kayabaNerve Jul 28, 2024
65efbf4
Support participating multiple times in the eVRF DKG
kayabaNerve Jul 29, 2024
fb7e966
Only participate once per key, not once per key share
kayabaNerve Jul 31, 2024
12f74e1
Rewrite processor key-gen around the eVRF DKG
kayabaNerve Aug 1, 2024
2f564c2
Finish routing the new key gen in the processor
kayabaNerve Aug 1, 2024
d3f0378
Deduplicate and better document in processor key_gen
kayabaNerve Aug 1, 2024
b5bf70b
Update serai-processor tests to the new key gen
kayabaNerve Aug 2, 2024
9e716c0
Correct amount of yx coefficients, get processor key gen test to pass
kayabaNerve Aug 2, 2024
fc51c9b
Add embedded elliptic curve keys to Substrate
kayabaNerve Aug 3, 2024
5ed3559
Update processor key gen tests to the eVRF DKG
kayabaNerve Aug 3, 2024
58a435d
Have set_keys take signature_participants, not removed_participants
kayabaNerve Aug 4, 2024
54eefbd
Update the coordinator binary for the new DKG
kayabaNerve Aug 4, 2024
1b76133
Add sensible Debug to key_gen::[Processor, Coordinator]Message
kayabaNerve Aug 5, 2024
f08faea
Have the DKG explicitly declare how to interpolate its shares
kayabaNerve Aug 5, 2024
9e8e134
Replace Interpolation::None with Interpolation::Constant
kayabaNerve Aug 5, 2024
e74c8f3
Get coordinator tests to pass
kayabaNerve Aug 5, 2024
2ae2883
Update spec to the new DKG
kayabaNerve Aug 5, 2024
89fc88b
Get clippy to pass across the repo
kayabaNerve Aug 6, 2024
b8912e4
cargo machete
kayabaNerve Aug 6, 2024
8de696f
Add an extra sleep to ensure expected ordering of `Participation`s
kayabaNerve Aug 6, 2024
3042697
Update orchestration
kayabaNerve Aug 6, 2024
d943e03
Remove bad panic in coordinator
kayabaNerve Aug 6, 2024
8c50a31
Improve documentation on functions
kayabaNerve Aug 6, 2024
c790efa
Update TX size limit
kayabaNerve Aug 6, 2024
f27fb9b
Correct error in the Processor spec document
kayabaNerve Aug 6, 2024
ec62930
Update a few comments in the validator-sets pallet
kayabaNerve Aug 6, 2024
e9d09ef
Send/Recv Participation one at a time
kayabaNerve Aug 6, 2024
dbf32d5
Correct ThresholdKeys serialization in modular-frost test
kayabaNerve Aug 6, 2024
01de73e
Updating existing TX size limit test for the new DKG parameters
kayabaNerve Aug 6, 2024
470b5f7
Increase time allowed for the DKG on the GH CI
kayabaNerve Aug 6, 2024
756db82
Correct construction of signature_participants in serai-client tests
kayabaNerve Aug 12, 2024
0fe7360
Further contextualize DkgConfirmer by ValidatorSet
kayabaNerve Aug 14, 2024
843396f
Add necessary calls to set_embedded_elliptic_curve_key in coordinator…
kayabaNerve Aug 15, 2024
5f1fcff
Correct shimmed setting of a secq256k1 key
kayabaNerve Aug 15, 2024
e098369
Merge branch 'develop' into one-round-dkg
kayabaNerve Aug 15, 2024
6bc746e
cargo fmt
kayabaNerve Aug 15, 2024
35c54da
Don't use `[0; 32]` for the embedded keys in the coordinator rotation…
kayabaNerve Aug 15, 2024
1f093cf
Big-endian secq256k1 scalars
kayabaNerve Aug 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
Prev Previous commit
Next Next commit
Have set_keys take signature_participants, not removed_participants
Now no one is removed from the DKG. Only `t` people publish the key however.

Uses a BitVec for an efficient encoding of the participants.
kayabaNerve committed Aug 4, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit 58a435d4e986adb78c4eb2057cb7a62ab44bc6fe
8 changes: 6 additions & 2 deletions substrate/abi/Cargo.toml
Original file line number Diff line number Diff line change
@@ -16,8 +16,10 @@ rustdoc-args = ["--cfg", "docsrs"]
workspace = true

[dependencies]
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
scale-info = { version = "2", default-features = false, features = ["derive"] }
bitvec = { version = "1", default-features = false, features = ["alloc", "serde"] }

scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive", "bit-vec"] }
scale-info = { version = "2", default-features = false, features = ["derive", "bit-vec"] }

borsh = { version = "1", default-features = false, features = ["derive", "de_strict_order"], optional = true }
serde = { version = "1", default-features = false, features = ["derive", "alloc"], optional = true }
@@ -39,6 +41,8 @@ serai-signals-primitives = { path = "../signals/primitives", version = "0.1", de

[features]
std = [
"bitvec/std",

"scale/std",
"scale-info/std",

2 changes: 1 addition & 1 deletion substrate/abi/src/validator_sets.rs
Original file line number Diff line number Diff line change
@@ -11,8 +11,8 @@ use serai_validator_sets_primitives::*;
pub enum Call {
set_keys {
network: NetworkId,
removed_participants: BoundedVec<SeraiAddress, ConstU32<{ MAX_KEY_SHARES_PER_SET / 3 }>>,
key_pair: KeyPair,
signature_participants: bitvec::vec::BitVec<u8, bitvec::order::Lsb0>,
signature: Signature,
},
set_embedded_elliptic_curve_key {
2 changes: 2 additions & 0 deletions substrate/client/Cargo.toml
Original file line number Diff line number Diff line change
@@ -20,6 +20,8 @@ workspace = true
zeroize = "^1.5"
thiserror = { version = "1", optional = true }

bitvec = { version = "1", default-features = false, features = ["alloc", "serde"] }

hex = "0.4"
scale = { package = "parity-scale-codec", version = "3" }
serde = { version = "1", features = ["derive"], optional = true }
7 changes: 2 additions & 5 deletions substrate/client/src/serai/validator_sets.rs
Original file line number Diff line number Diff line change
@@ -181,17 +181,14 @@ impl<'a> SeraiValidatorSets<'a> {

pub fn set_keys(
network: NetworkId,
removed_participants: sp_runtime::BoundedVec<
SeraiAddress,
sp_core::ConstU32<{ primitives::MAX_KEY_SHARES_PER_SET / 3 }>,
>,
key_pair: KeyPair,
signature_participants: bitvec::vec::BitVec<u8, bitvec::order::Lsb0>,
signature: Signature,
) -> Transaction {
Serai::unsigned(serai_abi::Call::ValidatorSets(serai_abi::validator_sets::Call::set_keys {
network,
removed_participants,
key_pair,
signature_participants,
signature,
}))
}
14 changes: 4 additions & 10 deletions substrate/runtime/src/abi.rs
Original file line number Diff line number Diff line change
@@ -103,16 +103,13 @@ impl From<Call> for RuntimeCall {
Call::ValidatorSets(vs) => match vs {
serai_abi::validator_sets::Call::set_keys {
network,
removed_participants,
key_pair,
signature_participants,
signature,
} => RuntimeCall::ValidatorSets(validator_sets::Call::set_keys {
network,
removed_participants: <_>::try_from(
removed_participants.into_iter().map(PublicKey::from).collect::<Vec<_>>(),
)
.unwrap(),
key_pair,
signature_participants,
signature,
}),
serai_abi::validator_sets::Call::set_embedded_elliptic_curve_key {
@@ -289,14 +286,11 @@ impl TryInto<Call> for RuntimeCall {
_ => Err(())?,
}),
RuntimeCall::ValidatorSets(call) => Call::ValidatorSets(match call {
validator_sets::Call::set_keys { network, removed_participants, key_pair, signature } => {
validator_sets::Call::set_keys { network, key_pair, signature_participants, signature } => {
serai_abi::validator_sets::Call::set_keys {
network,
removed_participants: <_>::try_from(
removed_participants.into_iter().map(SeraiAddress::from).collect::<Vec<_>>(),
)
.unwrap(),
key_pair,
signature_participants,
signature,
}
}
7 changes: 5 additions & 2 deletions substrate/validator-sets/pallet/Cargo.toml
Original file line number Diff line number Diff line change
@@ -19,10 +19,11 @@ ignored = ["scale", "scale-info"]
workspace = true

[dependencies]
bitvec = { version = "1", default-features = false, features = ["alloc", "serde"] }
hashbrown = { version = "0.14", default-features = false, features = ["ahash", "inline-more"] }

scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
scale-info = { version = "2", default-features = false, features = ["derive"] }
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive", "bit-vec"] }
scale-info = { version = "2", default-features = false, features = ["derive", "bit-vec"] }

serde = { version = "1", default-features = false, features = ["derive", "alloc"] }

@@ -48,6 +49,8 @@ dex-pallet = { package = "serai-dex-pallet", path = "../../dex/pallet", default-

[features]
std = [
"bitvec/std",

"scale/std",
"scale-info/std",

38 changes: 11 additions & 27 deletions substrate/validator-sets/pallet/src/lib.rs
Original file line number Diff line number Diff line change
@@ -927,14 +927,15 @@ pub mod pallet {
pub fn set_keys(
origin: OriginFor<T>,
network: NetworkId,
removed_participants: BoundedVec<Public, ConstU32<{ MAX_KEY_SHARES_PER_SET / 3 }>>,
key_pair: KeyPair,
signature_participants: bitvec::vec::BitVec<u8, bitvec::order::Lsb0>,
signature: Signature,
) -> DispatchResult {
ensure_none(origin)?;

// signature isn't checked as this is an unsigned transaction, and validate_unsigned
// (called by pre_dispatch) checks it
let _ = signature_participants;
let _ = signature;

let session = Self::session(network).unwrap();
@@ -949,15 +950,6 @@ pub mod pallet {
Self::set_total_allocated_stake(network);
}

// This does not remove from TotalAllocatedStake or InSet in order to:
// 1) Not decrease the stake present in this set. This means removed participants are
// still liable for the economic security of the external network. This prevents
// a decided set, which is economically secure, from falling below the threshold.
// 2) Not allow parties removed to immediately deallocate, per commentary on deallocation
// scheduling (https://github.com/serai-dex/serai/issues/394).
for removed in removed_participants {
Self::deposit_event(Event::ParticipantRemoved { set, removed });
}
Self::deposit_event(Event::KeyGen { set, key_pair });

Ok(())
@@ -1070,7 +1062,7 @@ pub mod pallet {
fn validate_unsigned(_: TransactionSource, call: &Self::Call) -> TransactionValidity {
// Match to be exhaustive
match call {
Call::set_keys { network, ref removed_participants, ref key_pair, ref signature } => {
Call::set_keys { network, ref key_pair, ref signature_participants, ref signature } => {
let network = *network;

// Don't allow the Serai set to set_keys, as they have no reason to do so
@@ -1094,30 +1086,24 @@ pub mod pallet {
// session on this assumption
assert_eq!(Pallet::<T>::latest_decided_session(network), Some(current_session));

// This does not slash the removed participants as that'll be done at the end of the
// set's lifetime
let mut removed = hashbrown::HashSet::new();
for participant in removed_participants {
// Confirm this wasn't duplicated
if removed.contains(&participant.0) {
Err(InvalidTransaction::Custom(2))?;
}
removed.insert(participant.0);
}

let participants =
Participants::<T>::get(network).expect("session existed without participants");

// Check the bitvec is of the proper length
if participants.len() != signature_participants.len() {
Err(InvalidTransaction::Custom(2))?;
}

let mut all_key_shares = 0;
let mut signers = vec![];
let mut signing_key_shares = 0;
for participant in participants {
for (participant, in_use) in participants.into_iter().zip(signature_participants) {
let participant = participant.0;
let shares = InSet::<T>::get(network, participant)
.expect("participant from Participants wasn't InSet");
all_key_shares += shares;

if removed.contains(&participant.0) {
if !in_use {
continue;
}

@@ -1135,9 +1121,7 @@ pub mod pallet {
// Verify the signature with the MuSig key of the signers
// We theoretically don't need set_keys_message to bind to removed_participants, as the
// key we're signing with effectively already does so, yet there's no reason not to
if !musig_key(set, &signers)
.verify(&set_keys_message(&set, removed_participants, key_pair), signature)
{
if !musig_key(set, &signers).verify(&set_keys_message(&set, key_pair), signature) {
Err(InvalidTransaction::BadProof)?;
}

8 changes: 2 additions & 6 deletions substrate/validator-sets/primitives/src/lib.rs
Original file line number Diff line number Diff line change
@@ -99,12 +99,8 @@ pub fn musig_key(set: ValidatorSet, set_keys: &[Public]) -> Public {
}

/// The message for the set_keys signature.
pub fn set_keys_message(
set: &ValidatorSet,
removed_participants: &[Public],
key_pair: &KeyPair,
) -> Vec<u8> {
(b"ValidatorSets-set_keys", set, removed_participants, key_pair).encode()
pub fn set_keys_message(set: &ValidatorSet, key_pair: &KeyPair) -> Vec<u8> {
(b"ValidatorSets-set_keys", set, key_pair).encode()
}

pub fn report_slashes_message(set: &ValidatorSet, slashes: &[(Public, u32)]) -> Vec<u8> {