Skip to content

Commit 5496c63

Browse files
committed
[key-server] handle committee mode
1 parent 2054f39 commit 5496c63

File tree

13 files changed

+1043
-95
lines changed

13 files changed

+1043
-95
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ checkpoints_dir/*
8080
light_client.yaml
8181
docs/content/references/sui-api/sui-graphql/*
8282
docs/content/references/framework/**
83-
83+
*.example
8484
lcov.info
8585

8686
**/build/**

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/dkg-cli/README.md

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ sui client call --package $COMMITTEE_PKG --module seal_committee \
8383
```bash
8484
cargo run --bin dkg-cli create-message --my-address $MY_ADDRESS --committee-id $COMMITTEE_ID --network $NETWORK
8585

86-
# This creates a file: ./message_X.json (where X is your party ID).
86+
# This creates a file: ./message_P.json (where P is your party ID).
8787
```
8888

8989
5. Wait for the coordinator to announce phase 3 and share a directory `./dkg-messages` containing all messages. Process the directory locally.
@@ -98,9 +98,9 @@ PARTY_0_PARTIAL_PK=0x8ef79f15defb1ea58b5644aa1fccc79f6235d3fff425ebe9140c3fda8e4
9898
PARTY_1_PARTIAL_PK=0x810b3577cb1e6dd011f1f8e2561f0e4f3c05eb0918f388817156de1a87a00b2b43f1e892da1efd09192fa85d62f83c1308b04beba3ed4d42ce01865bbd4eed24942a9504df90dce40575b05014a7b953ca4ec17530fe4367c1815cb7aca10261
9999
PARTY_2_PARTIAL_PK=0x92bb786ec791646fe63e99917b88c33966c9380b61dac70e4518d4a95834b42cc9163eb2cb6d067279525400bc59d91b05e52d19846bdd55a143e2d7cc7365355563a0a4d2004c6d5511da2d102d64bf0b4a518597b01af1984bfe69e2f13da5
100100

101-
# Outputs new share, use it for MASTER_SHARE environment variable for step 7.
101+
# Outputs new share, use it for MASTER_SHARE_V0 environment variable for step 7.
102102
============YOUR PARTIAL KEY SHARE, KEEP SECRET=====================
103-
MASTER_SHARE=0x208cd48a92430eb9f90482291e5552e07aebc335d84b7b6371a58ebedd6ed036
103+
MASTER_SHARE_V0=0x208cd48a92430eb9f90482291e5552e07aebc335d84b7b6371a58ebedd6ed036
104104
```
105105

106106
6. Propose the committee onchain with locally finalized key server public key and partial public keys.
@@ -111,28 +111,31 @@ sui client call --package $COMMITTEE_PKG --module seal_committee \
111111
--args $COMMITTEE_ID "[x\"$PARTY_0_PARTIAL_PK\", x\"$PARTY_1_PARTIAL_PK\", x\"$PARTY_2_PARTIAL_PK\"]" x"$KEY_SERVER_PK"
112112
```
113113

114-
7. WIP TODO: Wait for the coordinator to announce that the DKG process is completed and the created key server object ID. Update `key-server-config.yaml` containing `MY_ADDRESS` and `KEY_SERVER_OBJ_ID` and start the server with `MASTER_SHARE`.
114+
7. Wait for the coordinator to announce that the DKG process is completed and share the created key server object ID `KEY_SERVER_OBJ_ID`. Update `key-server-config.yaml` containing `MY_ADDRESS` and `KEY_SERVER_OBJ_ID` and start the server with `MASTER_SHARE_V0` (version 0 for fresh DKG).
115115

116-
Example config file:
116+
Example config file:
117117
```yaml
118118
server_mode: !Committee
119119
member_address: '<MY_ADDRESS>'
120120
key_server_obj_id: '<KEY_SERVER_OBJ_ID>'
121-
key_server_version: 0
121+
target_key_server_version: 0
122122
```
123123
124-
Example command to start server:
124+
Example command to start server:
125125
```bash
126-
CONFIG_PATH=crates/key-server/key-server-config.yaml MASTER_SHARE=0x208cd48a92430eb9f90482291e5552e07aebc335d84b7b6371a58ebedd6ed036 cargo run --bin key-server
126+
CONFIG_PATH=crates/key-server/key-server-config.yaml MASTER_SHARE_V0=0x208cd48a92430eb9f90482291e5552e07aebc335d84b7b6371a58ebedd6ed036 cargo run --bin key-server
127127
```
128128

129129
### Key Rotation Process
130130

131131
A key rotation process is needed when a committee wants to rotate a portion of its members. The continuing members (in both current and next committee) must meet the threshold of the current committee.
132132

133+
Assuming the key server committee mode version onchain is currently X and it is being rotated to X+1.
134+
133135
#### Coordinator Runbook
134136

135-
All steps are the same as the runbook for fresh DKG but step 2. Instead of calling `init_committee`, call `init_rotation`, where `CURRENT_COMMITTEE_ID` is the object ID of the current committee (e.g., `CURRENT_COMMITTEE_ID=0xaf2962d702d718f7b968eddc262da28418a33c296786cd356a43728a858faf80`).
137+
All steps are the same as the runbook for fresh DKG. Except:
138+
- Modified step 2: Instead of calling `init_committee`, call `init_rotation`, where `CURRENT_COMMITTEE_ID` is the object ID of the current committee (e.g., `CURRENT_COMMITTEE_ID=0xaf2962d702d718f7b968eddc262da28418a33c296786cd356a43728a858faf80`).
136139

137140
```bash
138141
# Example new members for rotation, along with ADDRESS_1, ADDRESS_0. Replace with your own.
@@ -148,6 +151,8 @@ sui client call --package $COMMITTEE_PKG --module seal_committee \
148151
COMMITTEE_ID=0x82283c1056bb18832428034d20e0af5ed098bc58f8815363c33eb3a9b3fba867
149152
```
150153

154+
- Added step 9: Monitor onchain that the new committee is finalized. Then announce DKG rotation is completed.
155+
151156
#### Member Runbook
152157

153158
1. Share with the coordinator your address (`MY_ADDRESS`). This is the wallet used for the rest of the onchain commands.
@@ -180,12 +185,12 @@ sui client call --package $COMMITTEE_PKG --module seal_committee \
180185

181186
4. Wait for the coordinator to announce phase 2.
182187

183-
a. For continuing members, run the CLI below to initialize the local state and create your message file. Must provide `--old-share` arg. Share the output file with the coordinator.
188+
a. For continuing members, run the CLI below to initialize the local state and create your message file. Must provide `--old-share` arg with your current version `X` master share. Share the output file with the coordinator.
184189

185190
```bash
186-
cargo run --bin dkg-cli create-message --my-address $MY_ADDRESS --committee-id $COMMITTEE_ID --network $NETWORK --old-share $MASTER_SHARE
191+
cargo run --bin dkg-cli create-message --my-address $MY_ADDRESS --committee-id $COMMITTEE_ID --network $NETWORK --old-share $MASTER_SHARE_VX
187192

188-
# This creates a file: ./message_X.json (where X is your party ID).
193+
# This creates a file: ./message_P.json (where P is your party ID).
189194
```
190195

191196
b. For new members, run the CLI below that initializes the local state. Do not provide old share.
@@ -201,14 +206,14 @@ cargo run --bin dkg-cli create-message --my-address $MY_ADDRESS --committee-id $
201206
```bash
202207
cargo run --bin dkg-cli process-all --messages-dir ./dkg-messages
203208

204-
# Outputs partial public keys, used for onchain proposal.
209+
# Outputs partial public keys, used for onchain proposal.
205210
PARTY_0_PARTIAL_PK=<...>
206211
PARTY_1_PARTIAL_PK=<...>
207212
PARTY_2_PARTIAL_PK=<...>
208213
PARTY_3_PARTIAL_PK=<...>
209214

210-
# Outputs new share, use it for NEXT_MASTER_SHARE environment variable for step 7.
211-
MASTER_SHARE=0x03899294f5e6551631fcbaea5583367fb565471adeccb220b769879c55e66ed9
215+
# Outputs new share (version X+1), to be used to start server at step 7.
216+
MASTER_SHARE_VX+1=0x03899294f5e6551631fcbaea5583367fb565471adeccb220b769879c55e66ed9
212217
```
213218

214219
6. Propose the committee onchain with locally finalized partial public keys.
@@ -219,17 +224,41 @@ sui client call --package $COMMITTEE_PKG --module seal_committee \
219224
--args $COMMITTEE_ID "[x\"$PARTY_0_PARTIAL_PK\", x\"$PARTY_1_PARTIAL_PK\", x\"$PARTY_2_PARTIAL_PK\", x\"$PARTY_3_PARTIAL_PK\"]" $CURRENT_COMMITTEE_ID
220225
```
221226

222-
7. WIP TODO: Update `key-server-config.yaml` to increment `KEY_SERVER_VERSION`. Start the server with existing `MASTER_SHARE` and `NEXT_MASTER_SHARE` (new share from the locally finalized DKG).
227+
7. Increment the version in `key-server-config.yaml` by 1, from `X` to `X+1`.
223228

224-
Example config file:
229+
Example config file:
225230
```yaml
226231
server_mode: !Committee
227232
member_address: '<MY_ADDRESS>'
228233
key_server_obj_id: '<KEY_SERVER_OBJ_ID>'
229-
key_server_version: <KEY_SERVER_VERSION>
234+
target_key_server_version: <X+1>
235+
```
236+
237+
a. For continuing members:
238+
239+
i. Restart server with both versioned keys (the current version onchain is still `X`, target is `X+1`). During this transition, the server watches for the current version onchain: If it is still `X`, serve request with `MASTER_SHARE_VX`. If onchain transitions to `X+1`, serve request with `MASTER_SHARE_VX+1`.
240+
241+
```bash
242+
CONFIG_PATH=crates/key-server/key-server-config.yaml \
243+
MASTER_SHARE_VX=<MASTER_SHARE_VX> \
244+
MASTER_SHARE_VX+1=<MASTER_SHARE_VX+1_OUTPUT_FROM_STEP_5> \
245+
cargo run --bin key-server
230246
```
231247

232-
Example command to start server:
248+
ii. Wait for coordinator to announce the DKG rotation is completed. Since now onchain version is indeed `X+1`, restart with only the version `X+1` key is sufficient:
249+
250+
```bash
251+
CONFIG_PATH=crates/key-server/key-server-config.yaml \
252+
MASTER_SHARE_VX+1=<MASTER_SHARE_VX+1_OUTPUT_FROM_STEP_5> \
253+
cargo run --bin key-server
254+
```
255+
256+
iii. Delete the old key `MASTER_SHARE_VX` from storage permanently.
257+
258+
b. For new members, since `X+1` is the first known key, so just need to start the server with it:
259+
233260
```bash
234-
CONFIG_PATH=crates/key-server/key-server-config.yaml MASTER_SHARE=0x208cd48a92430eb9f90482291e5552e07aebc335d84b7b6371a58ebedd6ed036 NEXT_MASTER_SHARE=0x03899294f5e6551631fcbaea5583367fb565471adeccb220b769879c55e66ed9 cargo run --bin key-server
261+
CONFIG_PATH=crates/key-server/key-server-config.yaml \
262+
MASTER_SHARE_VX+1=<MASTER_SHARE_VX+1_OUTPUT_FROM_STEP_5> \
263+
cargo run --bin key-server
235264
```

crates/key-server/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ hyper-util = "0.1.10"
5050
http-body-util = "0.1.2"
5151
futures = "0.3"
5252
seal-sdk = { path = "../seal-sdk" }
53+
seal-committee = { path = "../seal-committee" }
5354

5455
# sui grpc dep
5556
sui-rpc = { workspace = true }
@@ -61,3 +62,4 @@ tracing-test = "0.2.5"
6162
test-cluster = { workspace = true }
6263
sui-move-build = { workspace = true }
6364
temp-env = { version = "0.3", features = ["async_closure"] }
65+
fastcrypto-tbls = { workspace = true }

crates/key-server/key-server-config.yaml

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66
# network: Devnet
77
# network: !Custom
88
# node_url: 'url_to_node_endpoint' # Optional - see below
9-
# use_default_mainnet_for_mvr: true # Optional, default to true if not present,
10-
set this to false for mvr to resolve on testnet.
9+
# use_default_mainnet_for_mvr: true # Optional, default to true if not present, set this to false for mvr to resolve on testnet.
1110
#
1211
# Use Custom for production deployments. You must provide the node URL
1312
# in exactly one of these ways:
@@ -19,10 +18,12 @@ set this to false for mvr to resolve on testnet.
1918
network: Testnet
2019

2120

22-
# Server mode. The server can either work in Open/permissionless mode that
23-
# supports all packages, or in Permissioned mode that only supports
24-
# whitelisted packages .
21+
# Server mode:
22+
# 1) Open: Supports all policy packages.
23+
# 2) Permissioned: Supports only allowed policy packages.
24+
# 3) Committee: Supports all packages. Requires DKG setup for master key share.
2525
#
26+
# #### OPEN MODE ####
2627
# For the Open mode, set the registered key server object ID to be used, e.g.,:
2728
# server_mode: !Open
2829
# key_server_object_id: '0x0000000000000000000000000000000000000000000000000000000000000000'
@@ -31,7 +32,7 @@ network: Testnet
3132
server_mode: !Open
3233
key_server_object_id: '0x0000000000000000000000000000000000000000000000000000000000000000'
3334

34-
#
35+
# #### PERMISSIONED MODE ####
3536
# For the Permissioned mode, set the allowed clients and their configurations.
3637
# A client config contains:
3738
# - Client name - for debugging purposes only, can always be modified.
@@ -75,6 +76,33 @@ server_mode: !Open
7576
# package_ids:
7677
# - "0x3333333333333333333333333333333333333333333333333333333333333333"
7778

79+
# #### COMMITTEE MODE ####
80+
# See step 7 in the member runbook for fresh DKG and key rotation in details.
81+
#
82+
# Environment variables use versioned naming: MASTER_SHARE_VX
83+
#
84+
# - For active mode (onchain version = target version = X):
85+
# Must provide MASTER_SHARE_VX where X matches both onchain and target versions.
86+
# Example: For version 0, set MASTER_SHARE_V0, other versioned shares will be ignored.
87+
#
88+
# - For rotation mode (onchain version = X, target version = X+1):
89+
# Must provide MASTER_SHARE_VX and MASTER_SHARE_VX+1.
90+
# The server uses MASTER_SHARE_VX and automatically switches to MASTER_SHARE_VX+1
91+
# when the onchain version updates to X+1.
92+
# Example: For rotation from v1 to v2, set both MASTER_SHARE_V1 and MASTER_SHARE_V2.
93+
#
94+
# Example for a fresh DKG (MASTER_SHARE_V0 is set as environment variable):
95+
# server_mode: !Committee
96+
# member_address: '<MY_ADDRESS>'
97+
# key_server_obj_id: '<KEY_SERVER_OBJ_ID>'
98+
# target_key_server_version: 0
99+
#
100+
# Example for key rotation when onchain version is 1. (Both MASTER_SHARE_V1 and MASTER_SHARE_V2 are
101+
# set in environment variables):
102+
# server_mode: !Committee
103+
# member_address: '<MY_ADDRESS>'
104+
# key_server_obj_id: '<KEY_SERVER_OBJ_ID>'
105+
# target_key_server_version: 2
78106

79107
#### Optional advanced configurations ####
80108
#

crates/key-server/src/key_server_options.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use duration_str::deserialize_duration;
99
use semver::VersionReq;
1010
use serde::{Deserialize, Serialize};
1111
use std::time::Duration;
12+
use sui_sdk_types::Address;
1213
use sui_types::base_types::ObjectID;
1314
use tracing::info;
1415

@@ -47,6 +48,14 @@ pub enum ServerMode {
4748
// Master key is expected to by 32 byte HKDF seed
4849
client_configs: Vec<ClientConfig>,
4950
},
51+
Committee {
52+
member_address: Address,
53+
key_server_obj_id: Address,
54+
/// The target key server version set during rotation. During rotation, this can be exactly
55+
/// 1 greater than the current version. When rotation completes and the current version
56+
/// matches this version, MASTER_SHARE_V{target_key_server_version} will be used.
57+
target_key_server_version: u32,
58+
},
5059
}
5160

5261
/// Configuration for the RPC client.
@@ -255,7 +264,6 @@ impl KeyServerOptions {
255264
}
256265
Ok(())
257266
}
258-
259267
pub(crate) fn get_supported_key_server_object_ids(&self) -> Vec<ObjectID> {
260268
match &self.server_mode {
261269
ServerMode::Open {
@@ -273,6 +281,9 @@ impl KeyServerOptions {
273281
})
274282
.map(|c| c.key_server_object_id)
275283
.collect(),
284+
ServerMode::Committee {
285+
key_server_obj_id, ..
286+
} => vec![ObjectID::new(key_server_obj_id.into_inner())],
276287
}
277288
}
278289
}
@@ -378,10 +389,9 @@ server_mode: !Open
378389
}
379390
}
380391

381-
#[test]
382-
fn test_parse_permissioned_config() {
392+
#[tokio::test]
393+
async fn test_parse_permissioned_config() {
383394
use std::str::FromStr;
384-
385395
let valid_configuration = r#"
386396
network: Mainnet
387397
sdk_version_requirement: '>=0.2.7'

0 commit comments

Comments
 (0)