1
1
# Reference implementation of BIP DKG.
2
- from typing import Tuple , List , Optional , NamedTuple , NewType
2
+ from typing import Tuple , List , NamedTuple , NewType
3
3
4
4
from secp256k1ref .secp256k1 import Scalar
5
5
from secp256k1ref .bip340 import schnorr_sign , schnorr_verify
15
15
InvalidRecoveryDataError ,
16
16
DeserializationError ,
17
17
DuplicateHostpubkeyError ,
18
+ SessionNotFinalizedError ,
18
19
)
19
20
20
21
@@ -195,29 +196,28 @@ def signer_step2(
195
196
196
197
def signer_finalize (
197
198
state2 : SignerState2 , cert : bytes
198
- ) -> Optional [ Tuple [DKGOutput , RecoveryData ] ]:
199
- """A return value of None indicates that the DKG session has not completed
200
- successfully from our point of view.
199
+ ) -> Tuple [DKGOutput , RecoveryData ]:
200
+ """A SessionNotFinalizedError indicates that finalizing the DKG session was
201
+ not successful from our point of view.
201
202
202
- WARNING: Even when obtaining a return value of None, you MUST NOT conclude
203
- that the DKG session has failed from the point of view of other
204
- participants, and as a consequence, you MUST NOT erase your seed.
203
+ WARNING: Even when obtaining this exception, you MUST NOT conclude that the
204
+ DKG session has failed, and as a consequence, you MUST NOT erase your seed.
205
205
206
206
The underlying reason is that it is possible that some other participant
207
207
deems the DKG session successful, and uses the resulting threshold public
208
208
key (e.g., by sending funds to it.) That other participant can, at any point
209
209
in the future (e.g., when initiating a signing sessions), convince us of the
210
- success of the DKG session by presenting a public backup that is accepted by
211
- `signer_recover`."""
210
+ success of the DKG session by presenting recovery data for which
211
+ `signer_recover` succeeds and produces the expected session parameters ."""
212
212
(params , eta , dkg_output ) = state2
213
213
if not certifying_eq_verify (params .hostpubkeys , eta , cert ):
214
- return None
214
+ raise SessionNotFinalizedError
215
215
return dkg_output , RecoveryData (eta + cert )
216
216
217
217
218
218
async def signer (
219
219
chan : SignerChannel , seed : bytes , hostseckey : bytes , params : SessionParams
220
- ) -> Optional [ Tuple [DKGOutput , RecoveryData ] ]:
220
+ ) -> Tuple [DKGOutput , RecoveryData ]:
221
221
# TODO Top-level error handling
222
222
state1 , smsg1 = signer_step1 (seed , params )
223
223
chan .send (smsg1 )
@@ -228,9 +228,6 @@ async def signer(
228
228
chan .send (eq_round1 )
229
229
cert = await chan .receive ()
230
230
231
- # TODO: If signer_finalize fails, we should probably not just return None
232
- # but raise instead. Raising a specific exception is also better for
233
- # testing.
234
231
return signer_finalize (state2 , cert )
235
232
236
233
@@ -291,9 +288,7 @@ def coordinator_step(
291
288
return CoordinatorMsg (enc_cmsg , enc_shares_sums ), dkg_output , eta
292
289
293
290
294
- async def coordinator (
295
- chans : CoordinatorChannels , params : SessionParams
296
- ) -> Optional [DKGOutput ]:
291
+ async def coordinator (chans : CoordinatorChannels , params : SessionParams ) -> DKGOutput :
297
292
(hostpubkeys , t , params_id ) = params
298
293
n = len (hostpubkeys )
299
294
smsgs1 : List [SignerMsg1 ] = []
@@ -311,6 +306,6 @@ async def coordinator(
311
306
312
307
# TODO This should probably go to a coordinator_finalize function
313
308
if not certifying_eq_verify (hostpubkeys , eta , cert ):
314
- return None
309
+ raise SessionNotFinalizedError
315
310
316
311
return dkg_output
0 commit comments