last changed 08/17/2026
Rlauxe uses the following directory layout.
The auditrecord directory contains the publically available data, for use by verifiers. It should be published to a seperate bulletin board or web server. Files not in auditrecord are internal with formats that may change. Files in the private directory are typically only used in testing and must not be made public.
$topdir/
countyData.csv // optional - county contests only
countyContestData.csv // optional - county contests only
sortedCards.proto // optional? - same as sortedCards.csv in kotlin protobuf format
fastSampling.bin // optional? - (prn, styleId) in binary, used for fast sampling
auditrecord/
// election record - output of createElectionRecord
cardManifest.csv // AuditableCardCsv, may be zipped
contests.json // ContestsUnderAuditJson
electionInfo.json // ElectionInfoJson
cardPools.csv // optional - CardPoolCsv
cardStyles.json // optional - CardStylesJson
countyCardPools.csv // optional - CountyCardPoolCsv, when pools are from county totals
countyCvrPools.csv // optional - CountyCardPoolCsv, compare countyCardPools to generated cvrs, used by viewer (TODO remove from audit record?)
// auditRecord - output of createAuditRecord, after the seed has been chosen
auditCreationConfig.json // AuditCreationConfigJson
auditRoundConfig.json // auditRoundConfigJson ; prototype for auditRoundConfigX
sortedCards.csv // AuditableCardCsv, sorted by prn, may be zipped
roundX/
// output of runAuditRound
auditEstX.json // AuditRoundJson, an audit state with estimation, ready for auditing
auditRoundConfigX.json // auditRoundConfigJson, configuration for this round
auditStateX.json // AuditRoundJson, the results of the audit for this round
sampleCardsX.csv // AuditableCardCsv, complete sorted cards used for this round; matches samplePrnsX.csv
sampleMvrsX.csv // AuditableCardCsv, complete sorted mvrs used for this round; matches samplePrnsX.csv
samplePrnsX.json // SamplePrnsJson, complete sorted sample prns for this round
private/ (test only - not part of the public record)
sortedMvrs.csv // AuditableCardCsv, sorted by prn, matches sortedCards.csv, may be zipped
unsortedMvrs.csv // AuditableCardCsv (optional)
<county>.csv // optional - AuditableCardCsv for specific county
sortedChunks/
sorted-cards-part-X // optional - used for external sort of cardManifest.csv
Also see core/src/main/kotlin/org/cryptobiotic/rlauxe/persist/Publisher.kt.
1. CreateElectionRecord
The election information is contained in the following files. The EA (Election Authority) can modify these until satisfied that they are correct. Before the seed is chosen in step 2, they are digitally signed and published publically (aka committed to the Audit Record), and then may not be changed.
cardManifest.csv // AuditableCardCsv, may be zipped
contests.json // ContestsUnderAuditJson
electionInfo.json // ElectionInfoJson
cardPools.csv // optional - CardPoolCsv
cardStyles.json // optional - CardStylesJson
countyCardPools.csv // optional - CountyCardPoolCsv, when pools are from county totals
2. CreateAuditRecord : PRNG seed chosen, cards assigned PRNs
The PRNG seed is chosen, and all the cards in the card manifest are assigned a PRN in sequence by the PRNG. The cards are then sorted by PRN and written to sortedCards.csv. These are commited to the Audit Record. The PRNG seed can only be chosen once and the cards must be immediately committed.
auditCreationConfig.json // AuditCreationConfigJson
auditRoundConfig.json // auditRoundConfigJson ; prototype for auditRoundConfigX
sortedCards.csv // AuditableCardCsv, sorted by prn, may be zipped
3. Audit Round X Sample Estimation
The EA decides which contests are in the audit, and what the configuration parameters are for the round. The EA can calculate estimated sample sizes, and modify contest sample sizes and AuditRoundConfig parameters as often as they want. The EA cannot hand pick which ballots to sample, only modify how many samples for each contest are used in the round. This preserves the canonical ordering of each contest, see Deterministic sampling order for each Contest for more explanation.
Once the EA is satisfied with sample sizes and auditing parameters, the following files are committed to the Audit Record:
roundX/
auditRoundConfigX.json // the configuration parameters for round X
auditEstX.json // the estimation of sample sizes of the contests in this round
samplePrnsX.json // the chosen sample cards' prns for this round
4. Audit Round X gather MVRs
The physical ballots/cards are found that match samplePrnsX.json. These are hand-audited and their MVRs are written to sampleMvrsX.csv. The matching cards from the CardManifest are written to sampleCardsX.csv, for completeness and security. Before the audit is run, these are committed to the Audit Record:
roundX/
sampleMvrsX.csv // complete mvrs used for this round; matches samplePrnsX.csv
sampleCardsX.csv // complete cards used for this round; matches samplePrnsX.csv
5. Run Audit Round X
The audit is run for round X, and the following file is committed to the Audit Record:
roundX/
auditStateX.json // the results of the audit for this round
If not all contests are complete at the end of each round, then a new round begins and steps 3,4,5 are repeated.
This is an experimental feature for Belgium elections. Each componment is a single contest.
$compositedir/
$component1/
audit/
$component2/
audit/
...
Use AuditRecord.readFrom($compositedir). Each $component/audit is an AuditRecord. The contests from all components are put into the CompositeRecord. You can view and read, but not run audits on the CompositeRecord. Run audits independently on the individual components.
For simulation and testing, its convenient to do the audit in a single round, with all MVRs available, skipping the estimation steps, and keeping everything in memory (no persistence).
AuditWorkflow and its subclasses (esp PersistedWorkflow) implement auditing with rounds.
For real-world workflow examples, see createSfElection(), createBoulderElection(), createBelgiumClca(), and createColoradoElection() in the cases module.
Running an audit round is done through the RunRlaRoundCli, or from the viewer.