Skip to content

Commit 21c3a58

Browse files
authored
CIP-0137 | Fix protocol specifications (#1085)
* Fix typos in n2c local message notification * Replace 'blockNumber'/'TTL' fields with 'expiresAt' In order to provide a simpler message invalidation mechanism. * Add an explicit field for cold verification key in the message The cold verification key is not strictly necessary in the operational certificate. This allows to simplify the Haskell DMQ implementation and reuse the existing KES signature verification of the Ouroboros consensus implementation. * Fix update 'coldVerificationKey' type * Specify how message is signed with KES keys * Fix formatting issue in CDDL spec * Fix 'kesPeriod' type to 'word' * Fix 'kesPeriod' type to 'word64' * Fix line numbers in n2n submission message CDDL specs * Update message structure with payload and signature parts * Remove operational certificate and cold verification key from signed message payload * Remove 'MsgServerDone' message from n2c local message notification * Better explanation of the authentication of the message * Clarify structure of the message * Clarify the structure of the Operational Certificate
1 parent dbd1abe commit 21c3a58

File tree

1 file changed

+86
-72
lines changed

1 file changed

+86
-72
lines changed

CIP-0137/README.md

Lines changed: 86 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -126,46 +126,47 @@ stateDiagram-v2
126126
##### CDDL encoding specification
127127

128128
```cddl
129-
1
130-
2 messageSubmissionMessage
131-
3 = msgInit
132-
4 / msgRequestMessageIds
133-
5 / msgReplyMessageIds
134-
6 / msgRequestMessages
135-
7 / msgReplyMessages
136-
8 / msgDone
137-
9
138-
10 msgInit = [0]
139-
11 msgRequestMessageIds = [1, isBlocking, messageCount, messageCount]
140-
12 msgReplyMessageIds = [2, [ *messageIdAndSize ] ]
141-
13 msgRequestMessages = [3, messageIdList ]
142-
14 msgReplyMessages = [4, ]
143-
15 msgDone = [5, ]
144-
16
145-
17 isBlocking = false / true
146-
18 messageCount = word16
147-
19 messageId = bstr
148-
20 messageBody = bstr
149-
21 messageIdAndSize = [ messageId, messageSizeInBytes ]
150-
22 messageIdList = [ * messageId ]
151-
23 messageList = [ * message ]
152-
24 messageSizeInBytes = word32
153-
25 kesSignature = bstr
154-
26 operationalCertificate = bstr
155-
27 kesPeriod = word32
156-
28 blockNumber = word32
157-
29 ttl = word16
158-
30
159-
31 message = [
160-
32 messageId,
161-
33 messageBody,
162-
34 blockNumber,
163-
35 ttl,
164-
36 kesSignature,
165-
37 operationalCertificate,
166-
38 kesPeriod
167-
39 ]
168-
40
129+
messageSubmissionMessage
130+
= msgInit
131+
/ msgRequestMessageIds
132+
/ msgReplyMessageIds
133+
/ msgRequestMessages
134+
/ msgReplyMessages
135+
/ msgDone
136+
137+
msgInit = [0]
138+
msgRequestMessageIds = [1, isBlocking, messageCount, messageCount]
139+
msgReplyMessageIds = [2, [ *messageIdAndSize ] ]
140+
msgRequestMessages = [3, messageIdList ]
141+
msgReplyMessages = [4, ]
142+
msgDone = [5, ]
143+
144+
isBlocking = false / true
145+
messageCount = word16
146+
messageId = bstr
147+
messageBody = bstr
148+
messageIdAndSize = [ messageId, messageSizeInBytes ]
149+
messageIdList = [ * messageId ]
150+
messageList = [ * message ]
151+
messageSizeInBytes = word32
152+
kesSignature = bstr
153+
kesPeriod = word32
154+
operationalCertificate = [ bstr, word64, word64, bstr ]
155+
coldVerificationKey = bstr .size 32
156+
expiresAt = word32
157+
158+
messagePayload = [
159+
messageId
160+
, messageBody
161+
, kesPeriod
162+
, expiresAt
163+
]
164+
message = [
165+
bstr .cbor messagePayload
166+
, kesSignature
167+
, bstr .cbor operationalCertificate
168+
, coldVerificationKey
169+
]
169170
```
170171

171172
#### Inbound side and outbound side implementation
@@ -210,7 +211,10 @@ The protocol supports blocking and non-blocking requests:
210211

211212
##### Message invalidation mechanism
212213

213-
In order to bound the resource requirements needed to store the messages in a network node, their lifetime should be limited. A time to live can be set as a protocol parameter for each topic, and once the timespan has elapsed the message is discarded in the internal state of the network node. The time to live can be based on the timestamp of reception of the message on the network node or on the block number embedded in the message.
214+
In order to bound the resource requirements needed to store the messages in a network node, their lifetime should be limited. Thus, they carry an expiration date (formatted as a Unix timestamp) which must be checked before processing the message:
215+
216+
- the message will be invalidated when the local clock of the processing node exceeds the expiration date
217+
- an expiration date which expires too far in the future will be considered a protocol violation (the maximum allowed time to live is a protocol parameter for each topic which may be negotiated).
214218

215219
##### Cost of valid message storage
216220

@@ -241,7 +245,7 @@ For a total of **3,100** Cardano SPOs on the `mainnet`, on an average **50%** of
241245

242246
##### Message authentication mechanism
243247

244-
The message body is signed with the KES key of the SPO. This signature and the operational certificate of the SPO are appended to the message which is diffused.
248+
The payload part of the message (message id, message body, KES period and expiration timestamp fields encoded as CBOR) is signed with the KES key of the SPO. The message is composed of the aforementioned payload (encoded as CBOR bytes), the KES signature (raw bytes), the operational certificate (the KES public key, the issue number of the operational certificate, the KES period at the time of creation of the operational certificate and their cold signing key signature, encoded as CBOR bytes) and the cold verification key (raw bytes) are appended to the message.
245249

246250
Before being diffused to other peers, an incoming message must be verified by the receiving node. This is done with the following steps:
247251

@@ -302,15 +306,15 @@ The following tables gather figures about expected network load in the case of *
302306
| ---------------------- | ----------- | ----------- |
303307
| messageId | 32 B | 32 B |
304308
| messageBody | 360 B | 2,000 B |
305-
| blockNumber | 4 B | 4 B |
306-
| ttl | 2 B | 2 B |
307309
| kesSignature | 448 B | 448 B |
310+
| kesPeriod | 8 B | 8 B |
308311
| operationalCertificate | 304 B | 304 B |
309-
| kesPeriod | 4 B | 4 B |
312+
| coldVerificationKey | 4 B | 4 B |
313+
| expiresAt | 4 B | 4 B |
310314

311315
| Message | Lower bound | Upper bound |
312316
| ------- | ----------- | ----------- |
313-
| total | 1,154 B | 2,794 B |
317+
| total | 1,160 B | 2,800 B |
314318

315319
For a total of **3,100** Cardano SPOs on the `mainnet`, on an average **50%** of them will be eligible to send signatures (i.e. will win at least one lottery in the Mithril protocol). This means that if the full Cardano stake distribution is involved in the Mithril protocol, only **1,550** signers will send signatures at each round:
316320

@@ -463,28 +467,33 @@ msgDone = [3]
463467
464468
reason = invalid
465469
/ alreadyReceived
466-
/ ttlTooLarge
470+
/ expired
467471
/ other
468472
469473
invalid = [0, tstr]
470474
alreadyReceived = [1]
471-
ttlTooLarge = [2]
475+
expired = [2]
472476
other = [3, tstr]
473477
474478
messageId = bstr
475479
messageBody = bstr
476-
blockNumber = word32
477-
ttl = word16
478480
kesSignature = bstr
479-
operationalCertificate = bstr
480-
481+
kesPeriod = word64
482+
operationalCertificate = [ bstr, word64, word64, bstr ]
483+
coldVerificationKey = bstr .size 32
484+
expiresAt = word32
485+
486+
messagePayload = [
487+
messageId
488+
, messageBody
489+
, kesPeriod
490+
, expiresAt
491+
]
481492
message = [
482-
messageId,
483-
messageBody,
484-
blockNumber,
485-
ttl
486-
kesSignature,
487-
operationalCertificate
493+
bstr .cbor messagePayload
494+
, kesSignature
495+
, bstr .cbor operationalCertificate
496+
, coldVerificationKey
488497
]
489498
```
490499

@@ -502,6 +511,10 @@ The protocol follows a simple request-response pattern:
502511

503512
#### State machine
504513

514+
| Agency | |
515+
| ----------------- | ---------------------------------------- |
516+
| Client has Agency | StIdle |
517+
| Server has Agency | StBusyNonBlocking,StBusyBlocking, StDone |
505518
| Agency | |
506519
| ----------------- | ---------------------------------------- |
507520
| Client has Agency | StIdle |
@@ -520,7 +533,6 @@ stateDiagram-v2
520533
StBusyNonBlocking:::Green --> StIdle:::Blue : MsgReplyMessagesNonBlocking
521534
StIdle:::Blue --> StBusyBlocking:::Green : MsgRequestMessagesBlocking
522535
StBusyBlocking:::Green --> StIdle:::Blue : MsgReplyMessagesBlocking
523-
StBusyBlocking:::Green --> StDone:::Black : MsgServerDone
524536
StIdle:::Blue --> StDone:::Black : MsgClientDone
525537
526538
```
@@ -532,7 +544,6 @@ stateDiagram-v2
532544
- **MsgRequestMessagesBlocking**: The client asks for available messages and acknowledges old message ids. The server will only reply once there are available messages.
533545
- **MsgReplyMessagesBlocking([message])**: The server has received new messages and indicates if further message are available. In the blocking case, the reply is guaranteed to contain at least one message.
534546
- **MsgClientDone**: The client terminates the mini-protocol.
535-
- **MsgServerDone**: The server terminates the mini-protocol.
536547

537548
#### Transition table
538549

@@ -542,7 +553,6 @@ stateDiagram-v2
542553
| StBusyNonBlocking | MsgReplyMessagesNonBlocking | ([message], hasMore) | StIdle |
543554
| StIdle | MsgRequestMessagesBlocking | | StBusyBlocking |
544555
| StBusyBlocking | MsgReplyMessagesBlocking | [message] | StIdle |
545-
| StBusyBlocking | MsgServerDone | | StDone |
546556
| StIdle | MsgClientDone | | StDone |
547557

548558
##### CDDL Encoding Specification
@@ -556,27 +566,31 @@ localMessageNotificationMessage
556566
/ MsgReplyMessagesNonBlocking
557567
/ msgReplyMessagesBlocking
558568
/ msgClientDone
559-
/ msgServerDone
560569
561570
msgRequestMessages = [0, isBlocking]
562571
msgReplyMessagesNonBlocking = [1, messages, hasMore]
563572
msgReplyMessagesBlocking = [2, messages]
564573
msgClientDone = [3]
565-
msgServerDone = [4]
566574
567575
messageId = bstr
568576
messageBody = bstr
569-
blockNumber = word32
570-
ttl = word16
571577
kesSignature = bstr
572-
operationalCertificate = bstr
573-
578+
kesPeriod = word64
579+
operationalCertificate = [ bstr, word64, word64, bstr ]
580+
coldVerificationKey = bstr .size 32
581+
expiresAt = word32
582+
583+
messagePayload = [
584+
messageId
585+
, messageBody
586+
, kesPeriod
587+
, expiresAt
588+
]
574589
message = [
575-
messageId,
576-
messageBody,
577-
blockNumber,
578-
kesSignature,
579-
operationalCertificate
590+
bstr .cbor messagePayload
591+
, kesSignature
592+
, bstr .cbor operationalCertificate
593+
, coldVerificationKey
580594
]
581595
582596
hasMore = false / true

0 commit comments

Comments
 (0)