Contest Ballot Checkpoint¶
Description¶
Periodically, as ballots are collected, a summary of all newly collected ballots is published in a Contest Ballot Checkpoint document. Each checkpoint accumulates state over time, committing to the current set of accepted ballots via an SMT root and entry count, and optionally listing any ballots rejected in the same interval.
Checkpoint documents are chained together.
The final document in the sequence is indicated by the chain metadata.
Typically each Contest Ballot Checkpoint is made immutable by referencing it on the blockchain most applicable to the Contest.
Different blockchains will have different mechanisms for referencing checkpoint
documents.
For example, Cardano can encode a document_ref in on‑chain metadata,
signed by the ballot‑box (bulletin board) operator.
The blockchain record should be as close in time as practically possible to the creation of the Contest Ballot Checkpoint document to provide a reliable anchor for proofs of inclusion and auditability.
Validation¶
parametersmetadata MUST reference the Contest this checkpoint pertains to.refmetadata MUST reference the accepted Contest Ballots collected in the preceding interval by the bulletin board. Entries MUST be sorted by ascendingdocument_id:document_ver, regardless of the arrival time at the bulletin board.- Ballot boxes MUST reject ballots whose
document_id:document_verfall outside the contest’s allowed time window, or that are not close in time to when the ballot box received the ballot. - When present,
rejectionsMUST only contain recognized reasons and validdocument_refvalues of Contest Ballot documents; rejected ballots MUST NOT appear inreffor the same interval. smt-rootMUST be the Blake3 root hash of the canonical SMT containing all accepted ballots up to and including this checkpoint;smt-entriesMUST equal the total count of leaves in that SMT.chainMUST be intact and consistent: the previous checkpoint referenced bychainMUST exist, match type, id, and parameters, and have a lowerverand height exactly one less than this checkpoint.
Business Logic¶
Front End¶
- Not produced by the Front End.
- May be read to verify that a proof of inclusion validates against the published
smt-rootandsmt-entries.
Back End¶
- Validate that all referenced ballots exist and are valid for the contest.
- Ensure the document is signed by an authoritative bulletin‑board operator.
- Ensure all referenced ballots are for the same contest as
parameters. - Compute and verify
smt-rootandsmt-entriesagainst the current SMT state. - If present, validate
rejectionsreasons and that rejecteddocument_refs are Contest Ballot documents. - Ensure the chain is intact and consistent with the previous checkpoint.
- Ensure no previous checkpoint already chains to the same target (no forks within a single authoritative sequence).
COSE Header Parameters¶
- content type =
application/cbor - content-encoding =
[br]
Metadata¶
type¶
| Parameter | Value |
|---|---|
| Required | yes |
| Format | Document Type |
| Type | 58608925-bda3-47df-b39a-ae0d0a1dd6ed |
The document TYPE.
type Validation¶
MUST be a known document type.
id¶
| Parameter | Value |
|---|---|
| Required | yes |
| Format | Document Id |
Document ID, created the first time the document is created. This must be a properly created UUIDv7 which contains the timestamp of when the document was created.
id Validation¶
IF ver does not == id then a document with
id and ver being equal MUST exist.
ver¶
| Parameter | Value |
|---|---|
| Required | yes |
| Format | Document Ver |
The unique version of the document.
The first version of the document must set ver == id
ver represents new versions of the same document as it changes over time.
ver Validation¶
The document version must always be >= the document ID.
ref¶
| Parameter | Value |
|---|---|
| Required | yes |
| Format | Document Reference |
| Multiple References | True |
| Valid References | Contest Ballot |
Reference to a Linked Document or Documents. This is the primary hierarchical reference to a related document.
If a reference is defined as required, there must be at least 1 reference specified. Some documents allow multiple references, and they are documented as required.
The document reference serves two purposes:
- It ensures that the document referenced by an ID/Version is not substituted. In other words, that the document intended to be referenced, is actually referenced.
- It Allows the document to be unambiguously located in decentralized storage systems.
There can be any number of Document Locations in any reference. The currently defined locations are:
cid: A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).- Others may be added when further storage mechanisms are defined.
The document location does not guarantee that the document is actually stored. It only defines that if it were stored, this is the identifier that is required to retrieve it. Therefore it is required that Document References are unique and reproducible, given a documents contents.
ref Validation¶
The following must be true for a valid reference:
- The Referenced Document MUST Exist
- Every value in the
document_locatormust consistently reference the exact same document. - The
document_idanddocument_verMUST match the values in the referenced document.
parameters¶
| Parameter | Value |
|---|---|
| Required | yes |
| Format | Document Reference |
| Valid References | Contest Parameters |
| Linked Reference Metadata | ref |
A reference to the Parameters Document this document lies under.
parameters Validation¶
In addition to the validation performed for Document Reference type fields:
- Any linked referenced document that includes a
parametersmetadata must match theparametersof the referencing document, or a parent of thoseparameters.
For example, a linked reference to Contest Parameters is transitively a reference to
the Parameters document it references, and each parameters document they reference
until the Brand parameters document is reached.
The use case here is for Templates. The profile template, or proposal templates could be defined at any of these levels, and as long as they all refer to the same chain of parameters in the hierarchy they are all valid.
- The Document referenced by
ref- MUST contain
parametersmetadata; AND - MUST match the referencing documents
parametersvalue.
- MUST contain
chain¶
| Parameter | Value |
|---|---|
| Required | yes |
| Format | Chain Link |
An immutable link to the previous document in a chained sequence of documents.
Because ID/Ver only defines values for the current document, and is not intended
by itself to prevent insertion of documents in a sequence, the chain
metadata allows for the latest document to directly point to its previous iteration.
It also aids in discoverability, where the latest document may be pinned but prior documents can be discovered automatically by following the chain.
chain Validation¶
Chained Documents do not support collaborators. Any document which is attempted to be published in the sequence which is NOT published by the author of the first document in the sequence is fraudulent, and to be discarded.
In addition, the chained document MUST:
- Not have
collaborators; - Have the same
idas the document being chained to; - Have a
verthat is greater than theverbeing chained to; - Have the same
typeas the chained document; - Have
parametersmatch; - Have not be chaining to a document already chained to by another document;
- Have its absolute
heightexactly one more than theheightof the document being chained to.
IF any of these validations fail, then the entire sequence of documents is INVALID. Not just the current document.
Payload¶
The Payload is a CBOR document that MUST conform to the
contest-ballot-checkpoint CDDL schema.
Contents
-
stage(required)- Processing stage represented by this checkpoint.
- One of:
"bulletin-board" | "tally" | "audit".
-
smt-root(required)- Blake3 256‑bit digest of the root of the Sparse Merkle Tree (SMT)
containing all accepted ballot
document_refs up to and including this checkpoint.
- Blake3 256‑bit digest of the root of the Sparse Merkle Tree (SMT)
containing all accepted ballot
-
smt-entries(required)- The total number of documents (leaves) in the SMT at this checkpoint.
-
rejections(optional)- Map of
rejection-reason => [ document_ref, ... ]listing ballots rejected during this checkpoint interval. - Reasons are limited to:
"already-voted","obsolete-vote".
- Map of
-
encrypted-tally(optional)- Placeholder map of
document_ref => encrypted-tally-proposal-result. - May appear at later stages to commit to encrypted tally snapshots.
- Placeholder map of
-
tally(optional)- Placeholder map of
document_ref => tally-proposal-resultfor clear tally snapshots.
- Placeholder map of
-
drep-encryption-key(optional)- Placeholder for a DRep encryption key to allow decryption where required for audit or published results.
Notes
- The document
refmetadata lists the accepted Contest Ballots collected during the interval covered by this checkpoint; rejected ballots are listed underrejectionsand are not included inreffor that interval. - The SMT is cumulative across the chain; each checkpoint’s
smt-rootandsmt-entriescommit to all accepted ballots up to that point.
Schema¶
Payload CDDL Schema
; Catalyst Ballot Checkpoint data object.
;
; This serves as a checkpoint that collects new `contest-ballot-payload` documents
; that have been observed by a bulletin board.
;
; It will be created periodically during the voting period to allow proofs of inclusion
; to be firmly anchored and repeatably verifiable, and to allow voters or auditors to confirm
; a bulletin board acted honestly and included all valid ballots it detected.
;
; At another interval (which may be the same or different), a roll-up of the latest
; checkpoint is submitted to a blockchain to provide an immutable anchor of the
; ballots collected by a bulletin board up to that point in time.
; Catalyst Ballot Checkpoint Payload data object.
contest-ballot-checkpoint = {
"stage" : stage
"smt-root" : smt-root
"smt-entries" : smt-entries
? "rejections" : rejections
? "encrypted-tally" : encrypted-tally
? "tally" : tally
? "drep-encryption-key" : drep-encryption-key
}
; What stage in the ballot processing does this checkpoint represent.
stage = (
"bulletin-board" /
"tally" /
"audit"
)
; The SMT Root hash is a Blake 3 256bit digest Hash.
smt-root = blake3
; Blake3 Hash (Digest Size is determined by length of bytes)
blake3 = #6.32781(bytes)
; The Count of all Documents held by the SMT.
smt-entries = uint
; List of documents rejected at this checkpoint, grouped by reason.
rejections = {
+ rejection-reason => [ + document_ref ]
}
; The reason a document was rejected at this checkpoint.
rejection-reason = (
"already-voted" / ; Used to indicate a voter already voted in another system (ie, Jormungandr)
"obsolete-vote" ; Used to indicate a vote that was cast was replaced with a newer vote.
)
; Reference to a single Signed Document
document_ref = [
document_id
document_ver
document_locator
]
; Document ID
document_id = uuid_v7
; UUIDv7
uuid_v7 = #6.37(bytes .size 16)
; Document Version
document_ver = uuid_v7
; Where a document can be located, must be a unique identifier.
document_locator = {
"cid" : cid
}
; IPLD content identifier.
; Currently limited to SHA2-256 based CIDs.
cid = #6.42(bytes .abnfb ("cid" .det cbor-cid ))
; CIDv1 ABNF Constrained for SHA2-256
cbor-cid = '
cid = cidv1 codec-cbor sha2-256 digest-32 digest
cidv1 = %x00 %x01
codec-cbor = %x51
sha2-256 = %x12
digest-32 = %x20
digest = 32(%x00-FF)
'
; Placeholder of encrypted tally result.
encrypted-tally = {
+ document_ref => encrypted-tally-proposal-result
}
; Placeholder of encrypted tally result.
encrypted-tally-proposal-result = [ 1, undefined ]
; Placeholder of encrypted tally result.
tally = {
+ document_ref => tally-proposal-result
}
; Placeholder of encrypted tally result.
tally-proposal-result = [ 0, { + clear-choice : voting-power } ]
; Universal Unencrypted Choice
clear-choice = int
; Voting Power.
voting-power = int
; Placeholder of drep encryption key.
drep-encryption-key = undefined
Sub-schemas¶
Required Definition: stage
Required Definition: smt-root
Required Definition: blake3
Required Definition: smt-entries
Required Definition: rejections
; For any documents that were rejected for a defined reason,
; the list of document references which were rejected.
; List of documents rejected at this checkpoint, grouped by reason.
rejections = {
+ rejection-reason => [ + document_ref ]
}
; The reason a document was rejected at this checkpoint.
rejection-reason = (
"already-voted" / ; Used to indicate a voter already voted in another system (ie, Jormungandr)
"obsolete-vote" ; Used to indicate a vote that was cast was replaced with a newer vote.
)
; Reference to a single Signed Document
document_ref = [
document_id
document_ver
document_locator
]
; Document ID
document_id = uuid_v7
; UUIDv7
uuid_v7 = #6.37(bytes .size 16)
; Document Version
document_ver = uuid_v7
; Where a document can be located, must be a unique identifier.
document_locator = {
"cid" : cid
}
; IPLD content identifier.
; Currently limited to SHA2-256 based CIDs.
cid = #6.42(bytes .abnfb ("cid" .det cbor-cid ))
; CIDv1 ABNF Constrained for SHA2-256
cbor-cid = '
cid = cidv1 codec-cbor sha2-256 digest-32 digest
cidv1 = %x00 %x01
codec-cbor = %x51
sha2-256 = %x12
digest-32 = %x20
digest = 32(%x00-FF)
'
Required Definition: rejection-reason
; The reason a document was rejected at this checkpoint.
; The reason a document was rejected at this checkpoint.
rejection-reason = (
"already-voted" / ; Used to indicate a voter already voted in another system (ie, Jormungandr)
"obsolete-vote" ; Used to indicate a vote that was cast was replaced with a newer vote.
)
Required Definition: document_ref
; document_ref
; Reference to a single Signed Document
document_ref = [
document_id
document_ver
document_locator
]
; Document ID
document_id = uuid_v7
; UUIDv7
uuid_v7 = #6.37(bytes .size 16)
; Document Version
document_ver = uuid_v7
; Where a document can be located, must be a unique identifier.
document_locator = {
"cid" : cid
}
; IPLD content identifier.
; Currently limited to SHA2-256 based CIDs.
cid = #6.42(bytes .abnfb ("cid" .det cbor-cid ))
; CIDv1 ABNF Constrained for SHA2-256
cbor-cid = '
cid = cidv1 codec-cbor sha2-256 digest-32 digest
cidv1 = %x00 %x01
codec-cbor = %x51
sha2-256 = %x12
digest-32 = %x20
digest = 32(%x00-FF)
'
Required Definition: document_id
Required Definition: uuid_v7
Required Definition: document_ver
Required Definition: document_locator
; document_locator
; Where a document can be located, must be a unique identifier.
document_locator = {
"cid" : cid
}
; IPLD content identifier.
; Currently limited to SHA2-256 based CIDs.
cid = #6.42(bytes .abnfb ("cid" .det cbor-cid ))
; CIDv1 ABNF Constrained for SHA2-256
cbor-cid = '
cid = cidv1 codec-cbor sha2-256 digest-32 digest
cidv1 = %x00 %x01
codec-cbor = %x51
sha2-256 = %x12
digest-32 = %x20
digest = 32(%x00-FF)
'
Required Definition: cid
; IPLD content identifier.
; Also known as an IPFS CID.
; Currently limited to SHA2-256 based CIDs.
; See: https://docs.ipfs.tech/concepts/content-addressing/#what-is-a-cid
; https://github.com/ipld/cid-cbor/
; IPLD content identifier.
; Currently limited to SHA2-256 based CIDs.
cid = #6.42(bytes .abnfb ("cid" .det cbor-cid ))
; CIDv1 ABNF Constrained for SHA2-256
cbor-cid = '
cid = cidv1 codec-cbor sha2-256 digest-32 digest
cidv1 = %x00 %x01
codec-cbor = %x51
sha2-256 = %x12
digest-32 = %x20
digest = 32(%x00-FF)
'
Required Definition: cbor-cid
Required Definition: encrypted-tally
; The Result of an encrypted tally.
; Placeholder until formally defined.
; Placeholder of encrypted tally result.
encrypted-tally = {
+ document_ref => encrypted-tally-proposal-result
}
; Reference to a single Signed Document
document_ref = [
document_id
document_ver
document_locator
]
; Document ID
document_id = uuid_v7
; UUIDv7
uuid_v7 = #6.37(bytes .size 16)
; Document Version
document_ver = uuid_v7
; Where a document can be located, must be a unique identifier.
document_locator = {
"cid" : cid
}
; IPLD content identifier.
; Currently limited to SHA2-256 based CIDs.
cid = #6.42(bytes .abnfb ("cid" .det cbor-cid ))
; CIDv1 ABNF Constrained for SHA2-256
cbor-cid = '
cid = cidv1 codec-cbor sha2-256 digest-32 digest
cidv1 = %x00 %x01
codec-cbor = %x51
sha2-256 = %x12
digest-32 = %x20
digest = 32(%x00-FF)
'
; Placeholder of encrypted tally result.
encrypted-tally-proposal-result = [ 1, undefined ]
Required Definition: encrypted-tally-proposal-result
Required Definition: tally
; The Result of an encrypted tally.
; Placeholder until formally defined.
; Placeholder of encrypted tally result.
tally = {
+ document_ref => tally-proposal-result
}
; Reference to a single Signed Document
document_ref = [
document_id
document_ver
document_locator
]
; Document ID
document_id = uuid_v7
; UUIDv7
uuid_v7 = #6.37(bytes .size 16)
; Document Version
document_ver = uuid_v7
; Where a document can be located, must be a unique identifier.
document_locator = {
"cid" : cid
}
; IPLD content identifier.
; Currently limited to SHA2-256 based CIDs.
cid = #6.42(bytes .abnfb ("cid" .det cbor-cid ))
; CIDv1 ABNF Constrained for SHA2-256
cbor-cid = '
cid = cidv1 codec-cbor sha2-256 digest-32 digest
cidv1 = %x00 %x01
codec-cbor = %x51
sha2-256 = %x12
digest-32 = %x20
digest = 32(%x00-FF)
'
; Placeholder of encrypted tally result.
tally-proposal-result = [ 0, { + clear-choice : voting-power } ]
; Universal Unencrypted Choice
clear-choice = int
; Voting Power.
voting-power = int
Required Definition: tally-proposal-result
Required Definition: clear-choice
Required Definition: voting-power
Required Definition: drep-encryption-key
Signers¶
The following Admin roles may sign documents of this type:
- Bulletin Board Operator
Only the original author can update and sign a new version of documents.
Copyright¶
| Copyright | |
|---|---|
| License | This document is licensed under CC-BY-4.0 |
| Created | 2024-12-27 |
| Modified | 2025-11-10 |
| Authors | Alex Pozhylenkov alex.pozhylenkov@iohk.io |
| Nathan Bogale nathan.bogale@iohk.io | |
| Neil McAuliffe neil.mcauliffe@iohk.io | |
| Steven Johnson steven.johnson@iohk.io |
Changelog¶
0.1.5 (2025-11-03)¶
- Add Voting Ballots and Ballot Checkpoint Documents