Skip to content

Commit b671992

Browse files
committed
More comments on the protocol
1 parent 3a8cdae commit b671992

File tree

2 files changed

+221
-16
lines changed

2 files changed

+221
-16
lines changed

cocktail-dkg-ineiti.md

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
# Comments from ineiti (Linus Gasser)
2+
3+
I'm a hobby cryptographer involved as a
4+
software engineer in developing similar protocols like
5+
[CoSi](https://arxiv.org/pdf/1602.06997) and
6+
[Calypso](https://eprint.iacr.org/2018/209.pdf).
7+
Currently I'm working on a research grant on evaluating and proposing
8+
advanced cryptographic schemes for electronic identities:
9+
[Secure and Privacy-Preserving Credentials for E-ID](https://github.com/eid-privacy)
10+
This means that I have a pretty good grasp of elementar algebra and saw
11+
more than one way for a protocol to fail.
12+
This also means that I often follow a dead end and get distracted
13+
too often by pretty things...
14+
I hope these suggestions help, and I'm sorry I didn't read the
15+
papers and RFCs...
16+
17+
Also, I wrote this between commits 19270381332689124e406069cf197d90ee16fed5
18+
and 3a8cdae9a4598f724c5a79667ea4b3c24d0a34ec,
19+
so some things might be moot now.
20+
21+
Without other indication, I base myself on the definitions in
22+
[cocktail-dkg.md](./cocktail-dkg.md).
23+
24+
# DKG
25+
26+
This is probably a redundant explanation from the paper, but just to
27+
make sure I get the basics right, this is what I base myself on:
28+
29+
## Input and Output
30+
31+
From a high level, I suppose that every participant has the following
32+
inputs available to them, which have been received over a trusted
33+
channel:
34+
35+
- $n$ public keys $P_1$ .. $P_n$
36+
- the protocol $time$ as milliseconds since the Unix Epoch
37+
- a threshold $t$ who can sign a message
38+
- a minimal number $l$ of live participants needed to finish the protocol
39+
with $t <= l <= n$
40+
41+
The goal of the protocol is to produce the following information:
42+
43+
- the $context = H( "COCKTAIL-DKG-V0.1" | P_1 | ... | P_n | time | t | l )$
44+
- the group public key $Y$
45+
- $n$ secret keys $x_i$, one for each participant $i$
46+
- a common transcript $T = (context || Y || sig_{P_1}, \cdots, sig_{P_n})$
47+
48+
## Protocol Abort and Blame Assignment
49+
50+
If any of the participants detects a cryptographic error in
51+
any of the messages related to a $context$, they must abort
52+
the protocol. They must not accept any other message for this
53+
$context$, including signing requests.
54+
In case of an error from the coordinator, they must send the
55+
$BlameProof$ to all other participants.
56+
In case of an error from another participant, they must call
57+
$CoBlame(context, BlameProof)$.
58+
59+
To make sure that blame assignment works in a reliable manner
60+
without participants or the coordinator being able to blame
61+
an honest entity, care must be taken that all messages are
62+
signed and reliably assignable.
63+
Compared to Cocktail-DKG this means that there are some more
64+
signatures to avoid false blames.
65+
66+
A valid $BlameProof$ from participant $i$ looks like the following:
67+
68+
```math
69+
Blame = (i || context || FaultyMessage || AdditionalInfo)
70+
BlameProof = (Blame || Sig_{P_i}(Blame))
71+
```
72+
73+
To verify a $BlameProof$, only the public keys $P_1, \cdots, P_n$
74+
must be necessary.
75+
76+
The $AdditionalInfo$ is (probably) only used in `Round 2` of the
77+
protocol, in case of a decryption failure, or share verification
78+
failure. In that case, $AdditionalInfo = d_i$ WHICH IS OF COURSE
79+
STUPID, BECAUSE IT'S THIS PARTICIPANTS LONG-TERM PRIVATE KEY!
80+
So either there is another way to securely blame a decryption
81+
failure, or the ephemeral keys must be exchanged beforehand,
82+
and only these must be used for the ECDH.
83+
84+
## DKG Threat Model
85+
86+
For the participants and the coordinator, we consider the following threat model:
87+
88+
- the participants eventually send $msg_{1|i}$, the first step of the protocol
89+
- a number $l$ of _live_ participants follow through with the whole
90+
protocol
91+
- they have limited computing capabilities which does not allow
92+
them to find $x$ given $[ x ] B$
93+
- they will not deviate from the protocol if they can be correctly blamed
94+
(but will happily do so if an honest entity gets blamed)
95+
96+
With regard to the network:
97+
98+
- every message sent over the network eventually gets to the destination
99+
- there is no authentication, encryption, or verification of the message
100+
on the network
101+
- the adversary can read and modify all messages on the network, but will
102+
only do so if it doesn't lead the participants to abort the protocol or to
103+
stall the protocol
104+
105+
## Communication Optimization
106+
107+
The protocol can work in a completely peer-to-peer fashion with
108+
all the particpants communicating directly with each other.
109+
However, this leads to $O(n^2)$ messages to finish the protocol
110+
which can be prohibitive.
111+
For this reason we allow for a coordinator with the following
112+
set of operations.
113+
They are kept generic to allow for different kinds of implementations
114+
like a smart contract or a centralized server:
115+
116+
- $CoID$ is the identity of the coordinator which can be used
117+
to verify proofs of the coordinator.
118+
- $CoVerify(CoID, CoProof, msg)$ -> $()$ or $(Error)$ verifies if the
119+
$msg$ corresponds to the $CoProof$ created by the $CoID$. If the
120+
verification succeeds, it returns empty, else it returns an error.
121+
- $CoStart(P_1, ..., P_n, time, t, l)$ -> $(context)$ or $(Error)$
122+
starts a new DKG. The coordinator returns an error if one or more $P_i$
123+
are invalid curve points, or if $t <= l <= n$ does not hold.
124+
Else the coordinator stores the public
125+
keys and thresholds and returns the $context$.
126+
- $CoMsg1(context, i, msg_{1|i}, sig_{P_i})$ -> $()$ or $(Error)$
127+
allows each participant to store their $msg_{1|i}$. The coordinator
128+
returns an error if the context is not known, $i$ is out of bounds,
129+
the $sig_{P_i}$ does not verify the $msg_{1|i}$, or all
130+
$msg_{1|i}$ are already stored. Else the coordinator stores $msg_{1|i}$ and
131+
$sig_{P_i}$.
132+
- $CoMsg2(context, i)$ -> $(msg_{2|i}, CoProof_msg_{2|i})$ or $(Error)$
133+
allows each participant to retrieve their respective $msg_{2|i}$
134+
for the round 2 of the protocol. The coordinator returns an error if
135+
the context is not known, $i$ is out of bounds, not all participants
136+
sent their $msg_{1|i}$, or a valid $BlameProof$ exists.
137+
Else the coordinator returns $msg_{2|i}$ and the $CoProof_msg_{2|i}$.
138+
- $CoFinalize(context, i, sig_{P_i})$ -> $()$ or $(Error)$
139+
allows each participant to indicate that they successfully finished
140+
the round 2 of the protocol. The coordinator returns an error if the context
141+
is not known, $i$ is out of bounds, the $sig_{P_i}$ does not
142+
verify the message $(context | Y)$, or a valid $BlameProof$ exists.
143+
In case of success it returns empty.
144+
- $CoTranscript(context)$ -> $(T, CoProof_transcript)$ or $(Error)$
145+
allows anybody to get the transcript
146+
of the corresponding context. The coordinator returns an error if
147+
the $context$ is not known, less than $l$ participants finalized
148+
the protocol, or if a valid $BlameProof$ exists.
149+
Else it returns the group public key and at least $l$ valid signatures.
150+
- $CoBlame(context, BlameProof)$ -> $()$ or $(Error)$ aborts the
151+
protocol in case of a valid $BlameProof$. The coordinator returns
152+
an error if the $context$ is not known, or if the $BlameProof$ is
153+
invalid.
154+
155+
### Blockchain
156+
157+
In case of a blockchain, $CoID$ represents the blockchain identity, and
158+
$CoVerify$ must be able to verify that the $CoProof$ is actually
159+
stored somewhere on the blockchain.
160+
The $CoProof$ must point to the transaction and the block where the proof
161+
can be found.
162+
A smart contract can implement the different messages shown here, with the
163+
caveat that the cryptographic operations might be very expensive,
164+
depending on the type of smart contracts available.
165+
166+
### Central Server
167+
168+
For a central server, $CoID$ is the public key of the server,
169+
$CoProof$ is a signature on $msg$, and $CoVerify$ is a signature verification
170+
which returns either an error or an empty result if the verification
171+
is successful.
172+
173+
# Comments and questions
174+
175+
- The document should use section-# and subsection-#, so it would be easier
176+
to reference comments in a document like this :)
177+
- In the $msg2$ I don't understand the $C_{agg}$. I'm used to see "Aggregated"
178+
in elliptic curves as the sum of several elliptic curve points, but here it seems
179+
to be a list of $t-1$ points. However, I don't see how the participants
180+
in round 2 can then use the $C_{j,k}$ if they only have the sum of the points.
181+
So shouldn't the $msg_2$ have all $C_j$ in it?
182+
- Also for the $msg2$, which I changed to $msg_{2|i}$: In the `Protocol Messages`, you
183+
write that the coordinator returns the $msg_{2|i}$ to participant $i$. However, as
184+
described above, this message is not sufficient for participant $i$ to finish
185+
round 2 of the protocol. In the `Round 2` you state that the participants receive
186+
all $msg_{1|i}$ from all other participants, which is too much, as most of the
187+
encrypted shares will not be able to be decrypted. I propose to redefine
188+
$msg_{2|i}$ as follows:
189+
190+
```math
191+
msg_{2|i} = (C_1 || \cdots || C_n) || (PoP_1 || \cdots || Pop_n) || E_1 || \cdots || E_n || c_{1,i} || \cdots || c_{n,i}
192+
```
193+
194+
with all indexes $1 \cdots n$ excluding $i$. And then `Round 2` can state that
195+
each participant fetches $msg_{2|i}$ from the coordinator.
196+
197+
- I would put a visible link to the actual signing protocol!

cocktail-dkg.md

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[c2sp.org/cocktail-dkg](https://c2sp.org/cocktail-dkg)
44

55
- **Version**: v0.0.1
6-
- **Authors**:
6+
- **Authors**:
77
- [Daniel Bourdrez](https://github.com/bytemare)
88
- [Soatok Dreamseeker](https://github.com/soatok)
99
- [Tjaden Hess](https://github.com/tjade273), *[Trail of Bits](https://trailofbits.com)*
@@ -41,7 +41,7 @@ COCKTAIL is an independent derivative of ChillDKG intended to be used with any F
4141

4242
## Abstract
4343

44-
COCKTAIL-DKG is a standalone, three-round distributed key generation protocol for threshold signature schemes like
44+
COCKTAIL-DKG is a standalone, three-round distributed key generation protocol for threshold signature schemes like
4545
FROST.
4646

4747
COCKTAIL-DKG allows a group of $n$ participants to securely generate a shared group public key and individual secret
@@ -90,6 +90,7 @@ throughout the COCKTAIL-DKG protocol.
9090
- $x_i$: The final, long-lived secret share for participant $i$, where $x_i = \sum_{j=1}^{n} s_{j,i}$.
9191
- $Y_i$: The public verification share for participant $i$.
9292
- $Y$: The final group public key, where $Y = \sum_{j=1}^{n} C_{j,0}$.
93+
- $T$: The transcript of the DKG session.
9394

9495
### Operations
9596

@@ -131,7 +132,7 @@ encrypted shares for all other participants.
131132
* Format: $C_{i,0} || C_{i,1} || \cdots || C_{i,t-1}$
132133
* $PoP_i$: The Proof of Possession, which is a signature. The size depends on the signature scheme used by the
133134
ciphersuite.
134-
* $E_i$: The ephemeral public key, an elliptic curve point.
135+
* $E_i$: The ephemeral public key, an elliptic curve point.
135136
* It does not refer to isogenies. Here, E stands for "ephemeral".
136137
* $c_{i,j}$: An encrypted secret share. The size depends on the AEAD scheme used by the ciphersuite.
137138

@@ -141,7 +142,7 @@ The full message is the concatenation of these elements:
141142
msg_{1|i} = C_i || PoP_i || E_i || c_{i,1} || c_{i,2} || \cdots || c_{i,n}
142143
```
143144

144-
**2. $msg2$ (Coordinator -> All Participants, Round 2)**
145+
**2. $msg_{2|i}$ (Coordinator -> All Participants, Round 2)**
145146

146147
This message aggregates the public information from all participants.
147148

@@ -214,6 +215,7 @@ Each participant $i$ is assumed to have:
214215
using the secret $a_{i,0}$ as the private key and $C_{i,0}$ as the public key. The message to be signed is
215216
`context || C_i || E_i`. The specific signature algorithm is defined by the ciphersuite.
216217
5. **Compute and Encrypt Shares:** For each participant $j$ from $1$ to $n$:
218+
<<<<<<< HEAD
217219
1. **Compute Share:** Participant `i` computes the secret share $s_{i,j} = f_i(j)$.
218220
2. **Derive Key:** Participant `i` computes an ECDH shared secret with participant $j$'s static public key:
219221
$S_{i,j} = e_i * P_j$. It then derives a symmetric key and nonce for the AEAD.
@@ -226,21 +228,27 @@ Each participant $i$ is assumed to have:
226228
* $k_{i,j} = H("COCKTAIL-derive-key" || ikm)$
227229
* $iv_{i,j} = H("COCKTAIL-derive-nonce" || ikm)[0:24]$
228230
* Here, $H(x)$ is the underlying hash function (e.g., SHA-256).
231+
=======
232+
1. **Compute Share:** Participant $i$ computes the secret share $s_{i,j} = f_i(j)$.
233+
2. **Derive Key:** Participant $i$ computes an ECDH shared secret with participant $j$'s static public key:
234+
$S_{i,j} = e_i * P_j$. It then derives a symmetric key and nonce for the AEAD:
235+
$(k_{i,j}, iv_{i,j}) = H6(S_{i,j}, E_i, P_j, context)$.
236+
>>>>>>> a6797b1 (More comments on the protocol)
229237
3. **Encrypt Share:** Participant $i$ encrypts the share for participant $j$:
230238
$c_{i,j} = Enc(s_{i,j}, k_{i,j}, iv_{i,j})$.
231239
6. **Broadcast:** Participant $i$ sends their $msg_{1|i}$ to the coordinator.
232240

233241
### Round 2: Share Decryption and Verification
234242

235243
The coordinator waits to receive $msg_{1|i}$ from all $n$ participants. It then broadcasts a list of all received messages
236-
to every participant. Upon receiving the list of all $msg_{1|i}$ messages, each participant `i` performs the following
244+
to every participant. Upon receiving the list of all $msg_{1|i}$ messages, each participant $i$ performs the following
237245
steps:
238246

239-
1. **Verify All PoPs:** For each other participant $j$ from $1$ to $n$:
247+
1. **Verify All PoPs:** For each participant $j \neq i$ from $1$ to $n$:
240248
- Participant $i$ verifies the proof of possession $PoP_j$. The signature is checked against the message
241249
`context || C_j || E_j`, using participant $j$'s public commitment $C_{j,0}$ as the public key.
242250
- If any $PoP_j$ is invalid, participant $i$ **MUST** abort, identifying participant $j$ as malicious.
243-
2. **Decrypt and Verify Shares:** For each other participant $j$ from $1$ to $n$:
251+
2. **Decrypt and Verify Shares:** For each participant $j \neq i$ from $1$ to $n$:
244252
1. **Derive Key:** Participant $i$ computes the ECDH shared secret with participant $j$'s ephemeral public key:
245253
$S_{j,i} = d_i * E_j$. They then derive the symmetric key and nonce:
246254
* If the hash function has an output length at least 480 bits long:
@@ -324,7 +332,7 @@ The following categories cover the most common errors:
324332
3. **Protocol Logic Errors**:
325333
* **Description**: These errors relate to violations of the protocol's state machine or rules, such as:
326334
* A participant sending a message at the wrong time.
327-
* The coordinator broadcasting an inconsistent `msg2` (e.g., omitting a participant's data).
335+
* The coordinator broadcasting an inconsistent $msg_{2|i}$ (e.g., omitting a participant's data).
328336
* **Action**: These errors indicate a faulty participant or coordinator. The protocol **MUST** be aborted.
329337
If the error can be traced to a specific participant, they should be blamed.
330338

@@ -341,7 +349,7 @@ accountability in decentralized systems.
341349
* **Participant's Role and Public Proofs**: Participants **MUST** validate all data they receive.
342350
* If participant $i$ fails to verify a share $s_{j,i}$ from participant $j$, it **MUST** abort. To prove that $j$
343351
is cheating, participant $i$ can broadcast a blame message containing $j$'s index and the invalid share $s_{j,i}$.
344-
Any third party can then verify this claim by checking the VSS equation
352+
Any third party can then verify this claim by checking the VSS equation
345353
($s_{j,i} \cdot B = \sum_{k=0}^{t-1} i^k \cdot C_{j,k}$)
346354
using the public commitment $C_j$. A failure of this equation is a public and undeniable proof of $j$'s misbehavior.
347355
* Similarly, if a PoP from participant $j$ is invalid, this is also a publicly verifiable proof of misbehavior,
@@ -358,7 +366,7 @@ accountability in decentralized systems.
358366
broadcasting it, the PoP will fail for all other participants, who will blame $j$. However, in Round 3,
359367
participant $j$ will construct a transcript based on their *original*, valid $msg_{1|j}$. Their signature $sig_j$
360368
will be valid for their transcript but not for the altered transcript held by others. When this signature
361-
mismatch is detected, participant $j$ can reveal their original $msg_{1|j}$ (with its valid PoP) and their
369+
mismatch is detected, participant $j$ can reveal their original $msg_{1|j}$ (with its valid PoP) and their
362370
transcript signature. This evidence proves their honesty and definitively identifies the coordinator as malicious.
363371

364372
## Ciphersuites
@@ -370,12 +378,12 @@ Each ciphersuite defines a key derivation function $H6(x, pk1, pk2, extra)$, an
370378
and a decryption method $Dec(cipher, key, iv)$. Ciphersuites **SHOULD** use an AEAD mode for $Enc()$ and $Dec()$.
371379

372380
The choice of AEAD is guided by the principle of preventing nonce reuse. For ciphersuites where the underlying hash
373-
function provides a large enough output (at least 480 bits; e.g., SHA-512), we can derive both the 256-bit key and a
381+
function provides a large enough output (at least 480 bits; e.g., SHA-512), we can derive both the 256-bit key and a
374382
24-byte (192-bit) nonce (which is long enough to be generated randomly with a negligible chance of collision).
375383

376384
For ciphersuites based on SHA-256, where the output is smaller than 480 bits, we use $H6()$ to derive an Input Keying
377385
Material (IKM), which is then used with the underlying hash function with two different prefixes. For the key, we use
378-
$Sha256("COCKTAIL-derive-key" || ikm)$. For the nonce, we use the most significant 192 bits of
386+
$Sha256("COCKTAIL-derive-key" || ikm)$. For the nonce, we use the most significant 192 bits of
379387
$Sha256("COCKTAIL-derive-nonce" || ikm)$. The AEAD of choice for the SHA-256 based ciphersuites we specify here is
380388
[XAES-256-GCM](https://github.com/C2SP/C2SP/blob/main/XAES-256-GCM.md).
381389

@@ -463,9 +471,9 @@ The output of $H6$ is used to derive the key and nonce for the AEAD.
463471
confidentiality against an eavesdropper on the communication channel and authenticity to prevent a man-in-the-middle
464472
from tampering with the shares. The key is derived using an ECDH key exchange, ensuring that only the intended
465473
recipient can decrypt their share.
466-
- **Cofactor Security**: As noted in the [Ciphersuite-Specific Considerations](#ciphersuite-specific-considerations)
474+
- **Cofactor Security**: As noted in the [Ciphersuite-Specific Considerations](#ciphersuite-specific-considerations)
467475
section, curves like Ed25519 and Ed448 have small cofactors. It is critical that implementations use prime-order group
468-
abstractions like Ristretto255 and Decaf448 to prevent small subgroup attacks, where an attacker could submit a
476+
abstractions like Ristretto255 and Decaf448 to prevent small subgroup attacks, where an attacker could submit a
469477
low-order point to leak information.
470478
- **Participant Authentication**: Throughout the protocol, participants are authenticated to each other via their
471479
long-term static key pairs. The pairwise ECDH key agreement used to encrypt shares in Round 1 provides deniable
@@ -509,7 +517,7 @@ will be too.
509517
participants, which can be complex to set up. COCKTAIL-DKG removes this requirement by building in its own encryption
510518
layer (EncPedPop), making it usable over insecure, unauthenticated channels.
511519

512-
# Appendix A: Pseudocode
520+
# Appendix A: Pseudocode
513521

514522
This appendix provides a series of algorithms that describe the COCKTAIL-DKG protocol in a high-level,
515523
implementation-agnostic manner. The notation is meant to be illustrative rather than strictly formal.
@@ -657,7 +665,7 @@ function VerifyShare(s_ji, i, C_j, G, t):
657665
- ikm = H6(ecdh_secret, E_i, P_j, context)
658666
- key = H("COCKTAIL-derive-key" || ikm)
659667
- nonce = H("COCKTAIL-derive-nonce" || ikm)[0:24]
660-
- If the hash function used has an output size greater than equal to 480 bits, just split them:
668+
- If the hash function used has an output size greater than equal to 480 bits, just split them:
661669
- tmp = H6(ecdh_secret, E_i, P_j, context)
662670
- key = tmp[0:32] (32 bytes)
663671
- nonce = tmp[32:46] (24 bytes)

0 commit comments

Comments
 (0)