tempo_commonware_node/dkg/ceremony/
persisted.rs1use std::collections::BTreeMap;
4
5use bytes::Buf;
6use commonware_codec::{EncodeSize, RangeCfg, Read, Write, varint::UInt};
7use commonware_cryptography::{
8 bls12381::primitives::{group, poly::Public, variant::MinSig},
9 ed25519::PublicKey,
10};
11use commonware_utils::quorum;
12
13use super::IntermediateOutcome;
14
15#[derive(Clone, Default, Debug, PartialEq, Eq)]
17pub(in crate::dkg) struct State {
18 pub(super) num_players: u16,
19
20 pub(super) dealing: Option<Dealing>,
22
23 pub(super) received_shares: Vec<(PublicKey, Public<MinSig>, group::Share)>,
25
26 pub(super) dealing_outcome: Option<IntermediateOutcome>,
27
28 pub(super) outcomes: Vec<IntermediateOutcome>,
29}
30
31impl Write for State {
32 fn write(&self, buf: &mut impl bytes::BufMut) {
33 UInt(self.num_players).write(buf);
34 self.dealing.write(buf);
35 self.received_shares.write(buf);
36 self.dealing_outcome.write(buf);
37 self.outcomes.write(buf);
38 }
39}
40
41impl EncodeSize for State {
42 fn encode_size(&self) -> usize {
43 UInt(self.num_players).encode_size()
44 + self.dealing.encode_size()
45 + self.received_shares.encode_size()
46 + self.dealing_outcome.encode_size()
47 + self.outcomes.encode_size()
48 }
49}
50
51impl Read for State {
52 type Cfg = ();
54
55 fn read_cfg(
56 buf: &mut impl bytes::Buf,
57 _cfg: &Self::Cfg,
58 ) -> Result<Self, commonware_codec::Error> {
59 let num_players = UInt::read_cfg(buf, &())?.into();
60 let dealing = Option::<Dealing>::read_cfg(buf, &(quorum(num_players as u32) as usize))?;
61 let received_shares = Vec::<(PublicKey, Public<MinSig>, group::Share)>::read_cfg(
62 buf,
63 &(
64 RangeCfg::from(0..usize::MAX),
65 ((), quorum(num_players as u32) as usize, ()),
66 ),
67 )?;
68 let dealing_outcome = Option::<IntermediateOutcome>::read_cfg(buf, &())?;
69 let outcomes =
70 Vec::<IntermediateOutcome>::read_cfg(buf, &(RangeCfg::from(0..usize::MAX), ()))?;
71 Ok(Self {
72 num_players,
73 dealing,
74 received_shares,
75 dealing_outcome,
76 outcomes,
77 })
78 }
79}
80
81#[derive(Clone, Debug, PartialEq, Eq)]
86pub(super) struct Dealing {
87 pub(super) commitment: Public<MinSig>,
88 pub(super) shares: BTreeMap<PublicKey, group::Share>,
89 pub(super) acks: BTreeMap<PublicKey, super::Ack>,
90}
91
92impl EncodeSize for Dealing {
93 fn encode_size(&self) -> usize {
94 self.commitment.encode_size() + self.shares.encode_size() + self.acks.encode_size()
95 }
96}
97
98impl Read for Dealing {
99 type Cfg = usize;
100
101 fn read_cfg(buf: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, commonware_codec::Error> {
102 let commitment = Public::<MinSig>::read_cfg(buf, cfg)?;
103 let shares = BTreeMap::read_cfg(buf, &(RangeCfg::from(0..usize::MAX), ((), ())))?;
104 let acks = BTreeMap::read_cfg(buf, &(RangeCfg::from(0..usize::MAX), ((), ())))?;
105 Ok(Self {
106 commitment,
107 shares,
108 acks,
109 })
110 }
111}
112
113impl Write for Dealing {
114 fn write(&self, buf: &mut impl bytes::BufMut) {
115 self.commitment.write(buf);
116 self.shares.write(buf);
117 self.acks.write(buf);
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use std::collections::BTreeMap;
124
125 use crate::dkg::ceremony::{ACK_NAMESPACE, Ack, OUTCOME_NAMESPACE};
126
127 use super::{Dealing, State};
128 use commonware_codec::{DecodeExt as _, Encode as _, Read as _};
129 use commonware_cryptography::{
130 PrivateKeyExt as _, Signer,
131 bls12381::{dkg, primitives::variant::MinSig},
132 ed25519::{PrivateKey, PublicKey},
133 };
134 use commonware_utils::{quorum, set::Ordered, union};
135 use rand::{SeedableRng as _, rngs::StdRng};
136 use tempo_dkg_onchain_artifacts::IntermediateOutcome;
137
138 fn four_private_keys() -> Ordered<PrivateKey> {
139 vec![
140 PrivateKey::from_seed(0),
141 PrivateKey::from_seed(1),
142 PrivateKey::from_seed(2),
143 PrivateKey::from_seed(3),
144 ]
145 .into()
146 }
147
148 fn four_public_keys() -> Ordered<PublicKey> {
149 vec![
150 PrivateKey::from_seed(0).public_key(),
151 PrivateKey::from_seed(1).public_key(),
152 PrivateKey::from_seed(2).public_key(),
153 PrivateKey::from_seed(3).public_key(),
154 ]
155 .into()
156 }
157
158 fn dealing(dealer_index: usize) -> Dealing {
159 let (_, commitment, shares) = dkg::Dealer::<_, MinSig>::new(
160 &mut StdRng::from_seed([dealer_index as u8; 32]),
161 None,
162 four_public_keys(),
163 );
164 let shares = four_public_keys().iter().cloned().zip(shares).collect();
165
166 let mut acks = BTreeMap::new();
167 acks.insert(
168 four_public_keys()[0].clone(),
169 Ack::new(
170 &union(b"test", ACK_NAMESPACE),
171 four_private_keys()[0].clone(),
172 four_public_keys()[0].clone(),
173 42,
174 &four_public_keys()[dealer_index],
175 &commitment,
176 ),
177 );
178 acks.insert(
179 four_public_keys()[1].clone(),
180 Ack::new(
181 &union(b"test", ACK_NAMESPACE),
182 four_private_keys()[1].clone(),
183 four_public_keys()[1].clone(),
184 42,
185 &four_public_keys()[dealer_index],
186 &commitment,
187 ),
188 );
189 acks.insert(
190 four_public_keys()[2].clone(),
191 Ack::new(
192 &union(b"test", ACK_NAMESPACE),
193 four_private_keys()[2].clone(),
194 four_public_keys()[2].clone(),
195 42,
196 &four_public_keys()[dealer_index],
197 &commitment,
198 ),
199 );
200 acks.insert(
201 four_public_keys()[3].clone(),
202 Ack::new(
203 &union(b"test", ACK_NAMESPACE),
204 four_private_keys()[3].clone(),
205 four_public_keys()[3].clone(),
206 42,
207 &four_public_keys()[dealer_index],
208 &commitment,
209 ),
210 );
211 Dealing {
212 commitment,
213 shares,
214 acks,
215 }
216 }
217
218 fn dealing_outcome(dealer_index: usize) -> IntermediateOutcome {
219 let mut dealing = dealing(dealer_index);
220
221 IntermediateOutcome::new(
222 4,
223 &four_private_keys()[0],
224 &union(b"test", OUTCOME_NAMESPACE),
225 42,
226 dealing.commitment,
227 dealing.acks.values().cloned().collect(),
228 vec![dealing.shares.pop_last().unwrap().1],
229 )
230 }
231
232 #[test]
233 fn roundtrip_dealing() {
234 let bytes = dealing(0).encode();
235
236 assert_eq!(
237 Dealing::read_cfg(&mut bytes.as_ref(), &(quorum(4) as usize)).unwrap(),
238 dealing(0),
239 )
240 }
241
242 #[test]
243 fn roundtrip_state() {
244 let state = State {
245 num_players: 4,
246 dealing: Some(dealing(0)),
247 received_shares: vec![
248 (
249 four_public_keys()[1].clone(),
250 dealing(1).commitment,
251 dealing(1).shares[&four_public_keys()[0]].clone(),
252 ),
253 (
254 four_public_keys()[2].clone(),
255 dealing(2).commitment,
256 dealing(2).shares[&four_public_keys()[0]].clone(),
257 ),
258 ],
259 dealing_outcome: Some(dealing_outcome(0)),
260 outcomes: vec![dealing_outcome(1), dealing_outcome(2)],
261 };
262
263 let bytes = state.encode().freeze();
264
265 assert_eq!(State::decode(&mut bytes.as_ref()).unwrap(), state);
266 }
267}