diff --git a/dev/.documenter-siteinfo.json b/dev/.documenter-siteinfo.json index 6dfc5b4..f3bd4be 100644 --- a/dev/.documenter-siteinfo.json +++ b/dev/.documenter-siteinfo.json @@ -1 +1 @@ -{"documenter":{"julia_version":"1.10.2","generation_timestamp":"2024-03-30T00:09:01","documenter_version":"1.3.0"}} \ No newline at end of file +{"documenter":{"julia_version":"1.10.2","generation_timestamp":"2024-04-01T22:27:33","documenter_version":"1.3.0"}} \ No newline at end of file diff --git a/dev/assets/registration_sequence/index.html b/dev/assets/registration_sequence/index.html index 1a4820c..d65f9cb 100644 --- a/dev/assets/registration_sequence/index.html +++ b/dev/assets/registration_sequence/index.html @@ -10,4 +10,4 @@ Client ->> PeaceFounder: {ticket_id, member_id}_token PeaceFounder ->> Client: {member_id}_registrar Client ->> PeaceFounder: {pseudonym}_member - PeaceFounder ->> Client: inclusion_proof, {chain_state}_recorder + PeaceFounder ->> Client: inclusion_proof, {chain_state}_recorder diff --git a/dev/audit/index.html b/dev/audit/index.html index 836df4b..0b9df5e 100644 --- a/dev/audit/index.html +++ b/dev/audit/index.html @@ -16,4 +16,4 @@ @test checksum(ballotbox_archive, hasher) == ledger_root @test audit(braidchain_archive, ballotbox_archive, hasher) -@show tally(ballotbox_archive)

Note that this audit does not check the honesty of the registrar and that it has not admitted fake users to gain more influence in the election result. Properties being verified by the audit:

All these properties together ensure software independence so that the resulting tally does not depend on trust in the honest execution of either peacefounder service or braiders. In other words, the previously listed properties would not be altered if the adversary had full control over the peacefounder service and the braiders.

The immutability is ensured by voter's clients updating their consistency proof chain, which includes their vote. If the vote gets removed from a chain, every voter who cast their vote will get proof for an inconsistent ledger state called blame. The voter can make the blame public without revealing their vote, thus ensuring immutability and persistence after votes are published. The auditable part here is the votes signed with a pseudonym, which contract voters' clients to follow up at later periods with consistency proofs. On top of that, other monitors can synchronise the ballotbox ledger and add assurances that way.

+@show tally(ballotbox_archive)

Note that this audit does not check the honesty of the registrar and that it has not admitted fake users to gain more influence in the election result. Properties being verified by the audit:

All these properties together ensure software independence so that the resulting tally does not depend on trust in the honest execution of either peacefounder service or braiders. In other words, the previously listed properties would not be altered if the adversary had full control over the peacefounder service and the braiders.

The immutability is ensured by voter's clients updating their consistency proof chain, which includes their vote. If the vote gets removed from a chain, every voter who cast their vote will get proof for an inconsistent ledger state called blame. The voter can make the blame public without revealing their vote, thus ensuring immutability and persistence after votes are published. The auditable part here is the votes signed with a pseudonym, which contract voters' clients to follow up at later periods with consistency proofs. On top of that, other monitors can synchronise the ballotbox ledger and add assurances that way.

diff --git a/dev/audittools/index.html b/dev/audittools/index.html index b34a242..e3ed309 100644 --- a/dev/audittools/index.html +++ b/dev/audittools/index.html @@ -10,21 +10,13 @@ @test audit(ballotbox_archive, spec) @test audit(braidchain_archive) -@show tally(ballotbox_archive)

Note that spec is read from the DemeSpec record in the braidchain which can be trusted as the tree braidchain ledger checksum is listed within a proposal's anchor. The proposal is the first record in history tree for the ballotbox thus it is bound to ledger_root checksum and so demespec record is also tied to ledger_root.

For convinience an audit method is provided which audits both archives at the same time:

braidchain_archive = get_ballotbox_archive(uuid)
-ballotbox_archive = get_ballotbox_archive(uuid, proposal_index)[1:ledger_length]
+@show tally(ballotbox_archive)

Note that spec is read from the DemeSpec record in the braidchain which can be trusted as the tree braidchain ledger checksum is listed within a proposal's anchor. The proposal is the first record in history tree for the ballotbox thus it is bound to ledger_root checksum and so demespec record is also tied to ledger_root.

For convinience an audit method is provided which audits both archives at the same time:

audit(ledger::BraidChainLedger)
+audit(ledger::BallotBoxLedger)
 
-@test checksum(ballotbox_archive, hasher) == ledger_root
-@test audit(braidchain_archive, ballotbox_archive, hasher)
+isbinding(bbox::BallotBoxLedger, commit::Commit{BallotBoxState})
+isbinding(ledger::BraidChainLedger, commit::Commit{ChainState})
+
+isbinding(chain::BraidChainLedger, bbox::BraidChainLedger)
 
-@show tally(ballotbox_archive)

Note that this audit does not check honesty of the registrar that it have not admitted fake users to gain more influence in the ellection result. Properties being verified by the audit:

depend on a trust in honest execution of peacefounder service nor honesty of the braiders who provides new pseudonyms for the deme members. In other words the previously listed properties would not be altered if adversary would have a full control over the peacefounder service and the braiders.

The immutability is ensured from voter's clients updating their consistency proof chain which includes their vote. If the vote gets removed from a chain every single voter who had cast their vote would get a proof for inconsistent ledger state called blame. The blame can be made public by the voter without revealing it's vote and thus ensures immutability and also persitance after votes are published. The auditable part here are the votes themselves signed with pseudonym which contract voter's clients to follow up at latter periods with consistency proofs. On top of that, other monitors can synchronize the ballotbox ledger and add assurances that way.

source
PeaceFounder.Core.AuditTools.BallotBoxArchiveType
struct BallotBoxArchive
-    proposal::Proposal
-    seed::Digest
-    ledger::Vector{CastRecord}
-end

Represents a ballotbox ledger archive. Contains a proposal for which votes have been collected; seed initialized by collector and ledger containing all cast records.

source
PeaceFounder.Core.AuditTools.BraidChainArchiveType
struct BraidChainArchive
-    ledger::Vector{Transaction}
-end

Represents a braidchain ledger archive.

source
PeaceFounder.Core.AuditTools.archiveFunction
archive(ledger::BraidChainController)::BraidChainArchive
-archive(ledger::BallotBox)::BallotBoxArchive

Form an archive of braidchain or ballotbox which can be sent over wire to be audited.

source
PeaceFounder.Core.AuditTools.auditFunction
audit(archive::BallotBoxArchive, spec::CryptoSpec)

Check that recorded votes are consistent with proposal ballot and that cryptographic signature of every recorded vote is correct. –-

audit(archive::BraidChainArchive)

Check that the braidchain ledger is consistent. Runs through

- [`audit_members`](@ref)
-- [`audit_braids`](@ref) 
-- [`audit_proposals`](@ref)
-- [`audit_roster`](@ref)
-- [`audit_lots`](@ref)

audit(ballotbox_archive::BraidChainArchive, ballotbox_archive::BallotBoxArchive, hasher)

Audits each ledger seperatelly and then checks consistency between themselves: such as that only valid member pseudonyms have cast their votes, that proposal is available in the braidchain ledger.

source
PeaceFounder.Core.AuditTools.audit_braidsFunction
audit_braids(ledger::BraidChainArchive)

Individually check every braid and it's zero knowledge proof and it's consistency with the chain. For the latter, that input pseudonyms and relative generator to a braid come from a previous output braiding output and newly registered members.

source
PeaceFounder.Core.AuditTools.audit_membersFunction
audit_members(ledger::BraidChainArchive)

Check every member registration certificate consistency with the ledger. In particular: - Admission approved by a trusted entity at that time; - Membership approved by a admitted identity only once; - Every member psuedonym is generated with the current relative generator in the braidchain ledger;

source
PeaceFounder.Core.AuditTools.audit_proposalsFunction
audit_proposals(ledger::BraidChainArchive)

Check every proposal for it's consistency with the chain. In particular: - Every proposal is signed by a valid proposer at the time of inclusion in the ledger; - Anchor in within the proposal is consistent with the ledger; - Every proposal has a unique UUID as well as it's title is sufficiently different from previous ones;

source
PeaceFounder.Core.AuditTools.audit_rosterFunction
audit_roster(ledger::BraidChainArchive)

Check that every DemeSpec transaction in the ledger is correctly signed by the guardian.

source
PeaceFounder.Core.AuditTools.checksumFunction
checksum(ledger::Union{BraidChainArchive, BallotBoxArchive}, hasher)::Digest

Calculate a history tree root from a given ledger records. Meant to be used to check integrity of the received data.

source
+audit(chain::BraidChainLedger, bbox::BallotBoxLedger, commit::Commit{BallotBoxState}) +audit(chain::BraidChainLedger, bbox::BallotBoxLedger, root::Digest, N::Int = length(bbox))

Note that this audit does not check honesty of the registrar that it have admitted fake users to gain more influence in the ellection result. Properties being verified by the audit:

depend on a trust in honest execution of peacefounder service nor honesty of the braiders who provides new pseudonyms for the deme members. In other words the previously listed properties would not be altered if adversary would have a full control over the peacefounder service and the braiders.

The immutability is ensured from voter's clients updating their consistency proof chain which includes their vote. If the vote gets removed from a chain every single voter who had cast their vote would get a proof for inconsistent ledger state called blame. The blame can be made public by the voter without revealing it's vote and thus ensures immutability and also persitance after votes are published. The auditable part here are the votes themselves signed with pseudonym which contract voter's clients to follow up at latter periods with consistency proofs. On top of that, other monitors can synchronize the ballotbox ledger and add assurances that way.

source diff --git a/dev/client/index.html b/dev/client/index.html index 0c43528..151fc11 100644 --- a/dev/client/index.html +++ b/dev/client/index.html @@ -8,4 +8,4 @@

When a voter enters the proposal within the specified time window, it can go to ballot view by pressing Vote Now. The ballot view depends on the kind of Ballot used in the proposal. Since the votes are plaintext messages signed with pseudonyms, there are unlimited types of ballots that PeaceFounder can support, like - cardinal, preferential or budget-constrained ballots, some of which are planned to be implemented in the future.

A guard report is shown to the voter when the vote is cast. The guard contains three categories:

Left: a view for multiple question ballot. Right: a guard view where the voter sees ballot box identifier, a receipt for casting a vote and a commit of the current state of the ballot box.
-

The Merkle tree inclusion and consistency proof as a receipt to make a tamper-resistant bulletin board monitored by voters. So that undesirable votes can not be discarded when they have been recorded.

After the elections, each voter's client device checks whether the last cast vote is included in the final tally, together with a sequence number on the vote that prevents an adversary that has obtained the voter's private key from casting votes on voters' behalf without being noticed. This is done automatically as long as the client's device acts honestly, i.e., is not infected with malware.

In the case of malware, the fairness property maintained by the election authority and a timestamp on the casting receipt prevent malware on the voter's client from pointing to a substitute vote. Whereas the vote is cast as intended and counted as cast (important for revoting), a voter can check on the bulletin board with another computer using the receipt. If the malware is detected, the voter takes appropriate action for his device.

+

The Merkle tree inclusion and consistency proof as a receipt to make a tamper-resistant bulletin board monitored by voters. So that undesirable votes can not be discarded when they have been recorded.

After the elections, each voter's client device checks whether the last cast vote is included in the final tally, together with a sequence number on the vote that prevents an adversary that has obtained the voter's private key from casting votes on voters' behalf without being noticed. This is done automatically as long as the client's device acts honestly, i.e., is not infected with malware.

In the case of malware, the fairness property maintained by the election authority and a timestamp on the casting receipt prevent malware on the voter's client from pointing to a substitute vote. Whereas the vote is cast as intended and counted as cast (important for revoting), a voter can check on the bulletin board with another computer using the receipt. If the malware is detected, the voter takes appropriate action for his device.

diff --git a/dev/controllers/index.html b/dev/controllers/index.html index 1e19fdf..6b7b906 100644 --- a/dev/controllers/index.html +++ b/dev/controllers/index.html @@ -4,21 +4,21 @@ tickets::Vector{Ticket} signer::Signer hmac::HMAC -end

Represents a state for token registrar service. To initialize the service it's necessary to create a signer who can issue a valid admisssion certificates and a secret key with which a recruit client can exchange authorized messages. See also method generate(Registrar, spec).

Metadata is used as means to securelly deliver to the client most recent server specification.

Interface: select, hmac, hasher, key, id, tickets, in, enlist!, admit!, isadmitted, ticket_status

source
PeaceFounder.Server.Controllers.TicketType
mutable struct Ticket
+end

Represents a state for token registrar service. To initialize the service it's necessary to create a signer who can issue a valid admisssion certificates and a secret key with which a recruit client can exchange authorized messages. See also method generate(Registrar, spec).

Metadata is used as means to securelly deliver to the client most recent server specification.

Interface: select, hmac, hasher, key, id, tickets, in, enlist!, admit!, isadmitted, ticket_status

source
PeaceFounder.Server.Controllers.TicketType
mutable struct Ticket
     const ticketid::TicketID
     timestamp::DateTime
     attempt::UInt8
     token::Digest
     tokenid::String # 
     admission::Union{Admission, Nothing}
-end

Represents a ticket state for ticket with ticketid. timestamp represents time when the ticket have been issued by a registrar client in authorization system of choice, for instance, Registrars.jl; attempt is a counter with which token can be reset which is calculated with token(ticketid, attempt, hmac). Lastly admission contains a certified member pseudonym which was authetificated by the user with token.

source
Base.inMethod
in(ticketid::TicketID, registrar::Registrar)::Bool

Return true if there already is a ticket with ticketid.

source
PeaceFounder.Core.Model.generateMethod
generate(Registrar, spec::CryptoSpec)

Generate a new token registrar with unique signer and athorization key.

source
PeaceFounder.Core.Model.selectMethod
select(Admission, ticketid::TicketID, registrar::Registrar)::Union{Admission, Nothing}

Return admission for a ticket with given a given identity pseudonym from registrar. If no ticket with given id is found OR ticket is not yet admitted returns nothing.

source
PeaceFounder.Core.Model.selectMethod
select(Admission, ticketid::TicketID, registrar::Registrar)::Union{Admission, Nothing}

Return admission for a ticket with given ticketid from registrar. If no ticket with given ticketid is found OR ticket is not yet admitted returns nothing.

source
PeaceFounder.Core.Model.selectMethod
select(T, predicate::Function, registrar::Registrar)::Union{T, Nothing}

From a list of all registrar tickets return T <: Union{Ticket, Admission} for which predicate is true. If none succeds returns nothing.

source
PeaceFounder.Core.ProtocolSchema.isadmittedMethod
isadmitted(ticketid::TicketID, registrar::Registrar)

Check whether a ticket is already admitted. Returns false when either ticket is nonexistent or it's admission is nothing.

source
PeaceFounder.Server.Controllers.admit!Method
admit!(registrar::Registrar, id::Pseudonym, ticketid::TicketID)::Admission

Attempt to admit an identity pseudonym id for ticket ticketid. Authorization is expected to happen at the service layer using provided token in the invite. If a ticket is already registered return admission if it matches the provided id. Otherwise throe an error.

source
PeaceFounder.Server.Controllers.enlist!Method
enlist!(registrar::Registrar, ticketid::TicketID, timestamp::DateTime; route::URI=registrar.route)::Invite

Registers a new ticket with given TicketID and returns an invite. If ticket is already registered the same invite is returned. Throws an error when ticket is already registered.

source
PeaceFounder.Server.Controllers.hmacMethod
hmac(x)::HMAC

Return HMAC authorizer from a given object.

source
PeaceFounder.Server.Controllers.set_demehash!Method
set_demespec!(registrar::Registrar, spec::Union{Digest, DemeSpec})

Replace metadata for a registrar. Note when data is replaced all unfinalized tokens need to be flushed.

source
PeaceFounder.Server.Controllers.ticket_statusMethod
ticket_status(ticketid::TicketID, registrar::Registrar)::Union{TicketStatus, Nothing}

Return a ticket status for a ticketid. In case ticket is not found return nothing.

source
PeaceFounder.Server.Controllers.ticketsMethod
tickets(registrar::Registrar)::Vector{TicketID}

Return a list of registered ticket ids.

source
PeaceFounder.Server.Controllers.tokenMethod
token(ticketid::TicketID, hmac::HMAC)

Compute a recruit token for a given ticketid. Calculates it as token=Hash(Hash(0|key)|attempt|ticketid) where attempt is a counter for which token is issued.

Note: the token generation from key is made in order to support it's local computation on a remote server where QR code for registration is shown within organization website.

source

BraidChain

PeaceFounder.Server.Controllers.BraidChainControllerType
struct BraidChain
+end

Represents a ticket state for ticket with ticketid. timestamp represents time when the ticket have been issued by a registrar client in authorization system of choice, for instance, Registrars.jl; attempt is a counter with which token can be reset which is calculated with token(ticketid, attempt, hmac). Lastly admission contains a certified member pseudonym which was authetificated by the user with token.

source
Base.inMethod
in(ticketid::TicketID, registrar::Registrar)::Bool

Return true if there already is a ticket with ticketid.

source
PeaceFounder.Core.Model.generateMethod
generate(Registrar, spec::CryptoSpec)

Generate a new token registrar with unique signer and athorization key.

source
PeaceFounder.Core.Model.selectMethod
select(Admission, ticketid::TicketID, registrar::Registrar)::Union{Admission, Nothing}

Return admission for a ticket with given a given identity pseudonym from registrar. If no ticket with given id is found OR ticket is not yet admitted returns nothing.

source
PeaceFounder.Core.Model.selectMethod
select(Admission, ticketid::TicketID, registrar::Registrar)::Union{Admission, Nothing}

Return admission for a ticket with given ticketid from registrar. If no ticket with given ticketid is found OR ticket is not yet admitted returns nothing.

source
PeaceFounder.Core.Model.selectMethod
select(T, predicate::Function, registrar::Registrar)::Union{T, Nothing}

From a list of all registrar tickets return T <: Union{Ticket, Admission} for which predicate is true. If none succeds returns nothing.

source
PeaceFounder.Core.ProtocolSchema.isadmittedMethod
isadmitted(ticketid::TicketID, registrar::Registrar)

Check whether a ticket is already admitted. Returns false when either ticket is nonexistent or it's admission is nothing.

source
PeaceFounder.Server.Controllers.admit!Method
admit!(registrar::Registrar, id::Pseudonym, ticketid::TicketID)::Admission

Attempt to admit an identity pseudonym id for ticket ticketid. Authorization is expected to happen at the service layer using provided token in the invite. If a ticket is already registered return admission if it matches the provided id. Otherwise throe an error.

source
PeaceFounder.Server.Controllers.enlist!Method
enlist!(registrar::Registrar, ticketid::TicketID, timestamp::DateTime; route::URI=registrar.route)::Invite

Registers a new ticket with given TicketID and returns an invite. If ticket is already registered the same invite is returned. Throws an error when ticket is already registered.

source
PeaceFounder.Server.Controllers.hmacMethod
hmac(x)::HMAC

Return HMAC authorizer from a given object.

source
PeaceFounder.Server.Controllers.set_demehash!Method
set_demespec!(registrar::Registrar, spec::Union{Digest, DemeSpec})

Replace metadata for a registrar. Note when data is replaced all unfinalized tokens need to be flushed.

source
PeaceFounder.Server.Controllers.ticket_statusMethod
ticket_status(ticketid::TicketID, registrar::Registrar)::Union{TicketStatus, Nothing}

Return a ticket status for a ticketid. In case ticket is not found return nothing.

source
PeaceFounder.Server.Controllers.ticketsMethod
tickets(registrar::Registrar)::Vector{TicketID}

Return a list of registered ticket ids.

source
PeaceFounder.Server.Controllers.tokenMethod
token(ticketid::TicketID, hmac::HMAC)

Compute a recruit token for a given ticketid. Calculates it as token=Hash(Hash(0|key)|attempt|ticketid) where attempt is a counter for which token is issued.

Note: the token generation from key is made in order to support it's local computation on a remote server where QR code for registration is shown within organization website.

source

BraidChain

PeaceFounder.Server.Controllers.BraidChainControllerType
struct BraidChain
     members::Set{Pseudonym}
     ledger::BraidChainLedger
     spec::DemeSpec
     generator::Generator
     tree::HistoryTree
     commit::Union{Commit{ChainState}, Nothing}
-end

Represents a braidchain ledger with it's associated state. Can be instantitated with a demespec file using BraidChain(::DemeSpec) method.

Interface: push!, record!, state, length, list, select, roll, constituents, generator, commit, commit_index, ledger, leaf, root, ack_leaf, ack_root, members, commit!

source
Base.push!Method
push!(ledger::BraidChainController, t::Transaction)

Add an element to the BraidChainController bypassing transaction verification with the chain. This should only be used when the ledger is loaded from a trusted source like a local disk or when final root hash is validated with a trusted source.

source
HistoryTrees.leafMethod
leaf(ledger::BraidChainController, N::Int)::Digest

Return a ledger's element digest at given index.

source
HistoryTrees.rootMethod
root(ledger::BraidChainController[, N::Int])::Digest

Return a ledger root digest. In case when index is not given a current index is used.

source
PeaceFounder.Core.Model.commitMethod
commit(ledger::BraidChainController)

Return a current commit for a braichain.

source
PeaceFounder.Core.Model.generatorMethod
generator(ledger[, index])

Return a generator at braidchain ledger row index. If index is omitted return the current state value.

source
PeaceFounder.Core.Model.generatorMethod
generator(ledger::BraidChainController)

Return a current relative generator for a braidchain ledger.

source
PeaceFounder.Core.Model.isbindingMethod
isbinding(chain::BraidChainController, state::ChainState)::Bool

Check that chain state is consistent with braidchain ledger.

source
PeaceFounder.Core.Model.membersMethod
members(chain::BraidChainController, [n::Int])::Set

Return a set of member pseudonyms which at given anchor index can participate in voting or braiding.

source
PeaceFounder.Core.Model.selectMethod
select(T, predicate::Function, ledger::BraidChainController)::Union{T, Nothing}

Return a first element from a ledger with a type T which satisfies a predicate.

source
PeaceFounder.Core.Model.stateMethod
state(ledger::BraidChainController)

Return a current braidchain ledger state metadata.

source
PeaceFounder.Server.Controllers.ack_leafMethod
ack_leaf(ledger::BraidChainController, index::Int)::AckInclusion

Return a proof for record inclusion with respect to a current braidchain ledger history tree root.

source
PeaceFounder.Server.Controllers.ack_rootMethod
ack_root(ledger::BraidChainController, index::Int)

Return a proof for the ledger root at given index with respect to the current braidchain ledger history tree root.

source
PeaceFounder.Server.Controllers.commit!Method
commit!(ledger::BraidChainController, signer::Signer)

Commit a current braidchain ledger state with a signer's issued cryptographic signature.

source
PeaceFounder.Server.Controllers.constituentsMethod
constituents(ledger::BraidChainController)::Set{Pseudonym}

Return all member identity pseudonyms.

source
PeaceFounder.Server.Controllers.listMethod
list(T, ledger::BraidChainController)::Vector{Tuple{Int, T}}

List braidchain elements with a given type together with their index.

source
PeaceFounder.Server.Controllers.reset_tree!Method
reset_tree!(ledger::BraidChainController)

Recompute a chain tree hash.

source
PeaceFounder.Server.Controllers.rollMethod
roll(ledger::BraidChainController)::Vector{Membership}

Return all member certificates from a braidchain ledger.

source

BallotBox and PollingStation

PeaceFounder.Server.Controllers.BallotBoxControllerType
mutable struct BallotBoxController
+end

Represents a braidchain ledger with it's associated state. Can be instantitated with a demespec file using BraidChain(::DemeSpec) method.

Interface: push!, record!, state, length, list, select, roll, constituents, generator, commit, commit_index, ledger, leaf, root, ack_leaf, ack_root, members, commit!

source
Base.push!Method
push!(ledger::BraidChainController, t::Transaction)

Add an element to the BraidChainController bypassing transaction verification with the chain. This should only be used when the ledger is loaded from a trusted source like a local disk or when final root hash is validated with a trusted source.

source
HistoryTrees.leafMethod
leaf(ledger::BraidChainController, N::Int)::Digest

Return a ledger's element digest at given index.

source
HistoryTrees.rootMethod
root(ledger::BraidChainController[, N::Int])::Digest

Return a ledger root digest. In case when index is not given a current index is used.

source
PeaceFounder.Core.Model.commitMethod
commit(ledger::BraidChainController)

Return a current commit for a braichain.

source
PeaceFounder.Core.Model.generatorMethod
generator(ledger[, index])

Return a generator at braidchain ledger row index. If index is omitted return the current state value.

source
PeaceFounder.Core.Model.generatorMethod
generator(ledger::BraidChainController)

Return a current relative generator for a braidchain ledger.

source
PeaceFounder.Core.Model.isbindingMethod
isbinding(chain::BraidChainController, state::ChainState)::Bool

Check that chain state is consistent with braidchain ledger.

source
PeaceFounder.Core.Model.membersMethod
members(chain::BraidChainController, [n::Int])::Set

Return a set of member pseudonyms which at given anchor index can participate in voting or braiding.

source
PeaceFounder.Core.Model.selectMethod
select(T, predicate::Function, ledger::BraidChainController)::Union{T, Nothing}

Return a first element from a ledger with a type T which satisfies a predicate.

source
PeaceFounder.Core.Model.stateMethod
state(ledger::BraidChainController)

Return a current braidchain ledger state metadata.

source
PeaceFounder.Server.Controllers.ack_leafMethod
ack_leaf(ledger::BraidChainController, index::Int)::AckInclusion

Return a proof for record inclusion with respect to a current braidchain ledger history tree root.

source
PeaceFounder.Server.Controllers.ack_rootMethod
ack_root(ledger::BraidChainController, index::Int)

Return a proof for the ledger root at given index with respect to the current braidchain ledger history tree root.

source
PeaceFounder.Server.Controllers.commit!Method
commit!(ledger::BraidChainController, signer::Signer)

Commit a current braidchain ledger state with a signer's issued cryptographic signature.

source
PeaceFounder.Server.Controllers.constituentsMethod
constituents(ledger::BraidChainController)::Set{Pseudonym}

Return all member identity pseudonyms.

source
PeaceFounder.Server.Controllers.listMethod
list(T, ledger::BraidChainController)::Vector{Tuple{Int, T}}

List braidchain elements with a given type together with their index.

source
PeaceFounder.Server.Controllers.reset_tree!Method
reset_tree!(ledger::BraidChainController)

Recompute a chain tree hash.

source
PeaceFounder.Server.Controllers.rollMethod
roll(ledger::BraidChainController)::Vector{Membership}

Return all member certificates from a braidchain ledger.

source

BallotBox and PollingStation

PeaceFounder.Server.Controllers.BallotBoxControllerType
mutable struct BallotBoxController
     ledger::BallotBoxLedger
     voters::Set{Pseudonym} # better than members
     collector::Pseudonym
@@ -26,7 +26,7 @@
     queue::Vector{Vote}
     tree::HistoryTree
     commit::Union{Commit{BallotBoxState}, Nothing}
-end

Represents a ballot box for a proposal. Contains proposal, a set of eligiable voters a collector who collects the votes and a seed which is selected at random when the voting starts. queue contains a list of valid votes which yet to be comitted to a ledger. A history tree is built on leafs of ledger's receipts (see a receipt method). A commit contains a collector seal on the current ballotbox state.

Interface: reset_tree!, generator, uuid, ledger, spine, index, seed, leaf, root, receipt, commit, tally, set_seed!, ack_leaf, ack_root, ack_cast, commit_index, commit_state, push!, state, validate, record!, commit!

source
PeaceFounder.Server.Controllers.PollingStationType
struct PollingStation
+end

Represents a ballot box for a proposal. Contains proposal, a set of eligiable voters a collector who collects the votes and a seed which is selected at random when the voting starts. queue contains a list of valid votes which yet to be comitted to a ledger. A history tree is built on leafs of ledger's receipts (see a receipt method). A commit contains a collector seal on the current ballotbox state.

Interface: reset_tree!, generator, uuid, ledger, spine, index, seed, leaf, root, receipt, commit, tally, set_seed!, ack_leaf, ack_root, ack_cast, commit_index, commit_state, push!, state, validate, record!, commit!

source
PeaceFounder.Server.Controllers.PollingStationType
struct PollingStation
     halls::Vector{BallotBoxController}
     crypto::CryptoSpec
-end

Represents a pooling station which hosts ballotbox ledgers for every proposal collector manages.

Interface: init!, record!, commit!, commit, ack_leaf, ack_root, ack_cast, receipt, spine, ledger, tally, set_seed!

source
Base.getMethod
get(station::PollingStation, uuid::UUID)::BallotBoxController

Return a ballotbox ledger with a provided UUID. If none is found throws an error.

source
Base.getMethod
get(station::PollingStation, proposal::Digest)::BallotBoxController

Return a ballotbox which has proposal with provided digest.

source
Base.getindexMethod
getindex(ledger::BallotBoxController, index::Int)::CastRecord

Return a ledger record at provided index.

source
Base.lengthMethod
length(ledger::BallotBoxController)

Return a total length of the ledger including uncommited records in the queue.

source
Base.push!Method
push!(ledger::BallotBoxController, record::CastRecord)

Push a record to the ledger bypassing integrity checks. Used when loading the ledger from a trusted source such as local disk or an archive with a signed root cheksum.

source
HistoryTrees.leafMethod
leaf(ledger::BallotBoxController, N::Int)::Digest

Return a record digest used to form a history tree.

source
HistoryTrees.rootMethod
root(ledger::BallotBoxController[, N::Int])::Digest

Calculate a root for history tree at given index N. If index is not specified returns the current value.

source
PeaceFounder.Core.Model.commitMethod
commit(ledger::BallotBoxController)

Return a commit for the ballotbox ledger.

source
PeaceFounder.Core.Model.commitMethod
commit(station::PollingStation, uuid::UUID)::Commit

Return a ballotbox commit.

source
PeaceFounder.Core.Model.generatorMethod
generator(ledger::BallotBoxController)

Return a relative generator which members use to sign votes anchored by the proposal.

source
PeaceFounder.Core.Model.indexMethod
index(ledger::BallotBoxController)

Return the current index of the ledger. See also length.

source
PeaceFounder.Core.Model.isbindingMethod
isbinding(vote::Vote, ack::CastAck, hasher)

Check whether acknowledgment is bound to the provided vote.

source
PeaceFounder.Core.Model.receiptMethod
receipt(ledger::BallotBoxController, index::Int)::CastReceipt

Return a receipt for a ledger element.

source
PeaceFounder.Core.Model.receiptMethod
receipt(station::PollingStation, uuid::UUID, N::Int)::CastReceipt

Return a receipt for a record with index N at ballotbox with uuid.

source
PeaceFounder.Core.Model.seedMethod
seed(ledger::BallotBoxController)::Union{Digest, Nothing}

Return a random selected seed used in the voting.

source
PeaceFounder.Core.Model.tallyMethod
tally(station::PollingStation, uuid::UUID)

Compute a tally from ledger records a ballotbox with uuid.

source
PeaceFounder.Core.Model.uuidMethod
uuid(ledger::BallotBoxController)

Return a UUID of the proposal.

source
PeaceFounder.Core.Model.votersMethod
voters(ledger::BallotBoxController)

Return a list of member pseudonyms with which members authetificate their votes.

source
PeaceFounder.Server.Controllers.ack_castMethod
ack_cast(ledger::BallotBoxController, index::Int)::CastAck

Compute an acknowledgment for record inclusion at index.

source
PeaceFounder.Server.Controllers.ack_castMethod
ack_cast(station::PollingStation, uuid::UUID, N::Int)::CastAck

Return inclusion proof with receipt and current tree commit for a leaf at index N and ballotbox with uuid.

source
PeaceFounder.Server.Controllers.ack_leafMethod
ack_leaf(ledger::BallotBoxController, index::Int)::AckInclusion

Compute an inclusion proof ::AckInclusion for record element at given index.

source
PeaceFounder.Server.Controllers.ack_leafMethod
ack_leaf(station::PollingStation, uuid::UUID, N::Int)::AckInclusion

Return history tree inclusion proof for a tree leaf at index N in ballotbox with uuid.

source
PeaceFounder.Server.Controllers.ack_rootMethod
ack_root(ledger::BallotBoxController, index::Int)::AckConsistency

Compute a history tree consistency proof at index.

source
PeaceFounder.Server.Controllers.ack_rootMethod
ack_root(station::PollingStation, uuid::UUID, N::Int)::AckConsistency

Return history tree consitency proof tree root at index N in ballotbox with uuid.

source
PeaceFounder.Server.Controllers.commit!Method
commit!(ledger::BallotBoxController[, timestamp::DataTime], signer::Signer; with_tally=nothing)

Flushes ballotbox ledger's queue and creates a commit for a current ballotbox ledger state with provided timestamp and signer. A keyword argument with_tally has three values true|false to include or exclude a tally from a commited state and nothing which uses a previous commit preference.

source
PeaceFounder.Server.Controllers.commit!Method
commit!(station::PollingStation, uuid::UUID, collector::Signer; with_tally = nothing)

Select a ballotbox with provided uuid and commit it's state with collector.

source
PeaceFounder.Server.Controllers.commit_indexMethod
commit_index(ledger::BallotBoxController)::Union{Index, Nothing}

Index at which commit is issued. See also length and index

source
PeaceFounder.Server.Controllers.commit_stateMethod
commit_state(ledger::BallotBoxController)

Return a committed state for a ballotbox ledger.

source
PeaceFounder.Server.Controllers.init!Method
init!(station::PollingStation, proposal::Proposal, voters::Set{Pseudonym}[, collector::Pseudonym])

Creates a new ballotbox for given proposal with provided member pseudonyms at a relative generator anchored in the proposal. A collector is optional and provided only when it differs from one specified in the proposal.

source
PeaceFounder.Server.Controllers.ledgerMethod
ledger(ballotbox::BallotBoxController)::Vector{CastRecord}

Return all records from a ballotbox ledger.

source
PeaceFounder.Server.Controllers.ledgerMethod
ledger(station::PollingStation, uuid::UUID)::Vector{CastRecord}

Return a vector of records from a ballotbox with uuid.

source
PeaceFounder.Server.Controllers.record!Method
record!(ledger::BallotBoxController, record::CastRecord)

Check the vote in the record for validity and include that in the ledger directly bypassing queue. This method is useful for replaying and debugging ballotbox ledger state changes. See also record!

source
PeaceFounder.Server.Controllers.record!Method
record!(ledger::BallotBoxController, vote::Vote)

Check the vote for validity and pushes it to the queue. Returns an index N at which the vote will be recorded in the ledger. See also push!

source
PeaceFounder.Server.Controllers.record!Method
record!(station::PollingStation, uuid::UUID, vote::Vote)::Int

Records a vote in a ballotbox with provided proposal UUID. Throws an error if a ballotbox can't be found.

source
PeaceFounder.Server.Controllers.record!Method
record!(station::PollingStation, uuid::UUID, vote::Vote)::Int

Record a vote in a ballotbox found by proposal diggest stored in the vote. Throws an error if a ballotbox can't be found.

source
PeaceFounder.Server.Controllers.reset_tree!Method
reset_tree!(ledger::BallotBoxController)

Recompute history tree root and cache from the elements in the ledger. This is a useful for loading the ledger all at once.

source
PeaceFounder.Server.Controllers.set_seed!Method
set_seed!(ledger::BallotBoxController, seed::Digest)

Set's a seed of the ballotbox.

source
PeaceFounder.Server.Controllers.set_seed!Method
set_seed!(station::PollingStation, uuid::UUID, seed::Digest)

Sets a seed for a ballotbox with provided uuid.

source
PeaceFounder.Server.Controllers.spineMethod
spine(ledger::BallotBoxController)::Vector{Digest}

Return a history tree leaf vector.

source
PeaceFounder.Server.Controllers.spineMethod
spine(station::PollingStation, uuid::UUID)::Vector{Digest}

Return a leaf vector for a ballotbox with proposal uuid.

source
PeaceFounder.Server.Controllers.validateMethod
validate(ledger::BallotBoxController, vote::Vote)

Check that vote can be included in the ballotbox. Is well formed, signed by a member pseudonym and cryptographic signature is valid. Raises error if either of checks fail.

source
+end

Represents a pooling station which hosts ballotbox ledgers for every proposal collector manages.

Interface: init!, record!, commit!, commit, ack_leaf, ack_root, ack_cast, receipt, spine, ledger, tally, set_seed!

source
Base.getMethod
get(station::PollingStation, uuid::UUID)::BallotBoxController

Return a ballotbox ledger with a provided UUID. If none is found throws an error.

source
Base.getMethod
get(station::PollingStation, proposal::Digest)::BallotBoxController

Return a ballotbox which has proposal with provided digest.

source
Base.getindexMethod
getindex(ledger::BallotBoxController, index::Int)::CastRecord

Return a ledger record at provided index.

source
Base.lengthMethod
length(ledger::BallotBoxController)

Return a total length of the ledger including uncommited records in the queue.

source
Base.push!Method
push!(ledger::BallotBoxController, record::CastRecord)

Push a record to the ledger bypassing integrity checks. Used when loading the ledger from a trusted source such as local disk or an archive with a signed root cheksum.

source
HistoryTrees.leafMethod
leaf(ledger::BallotBoxController, N::Int)::Digest

Return a record digest used to form a history tree.

source
HistoryTrees.rootMethod
root(ledger::BallotBoxController[, N::Int])::Digest

Calculate a root for history tree at given index N. If index is not specified returns the current value.

source
PeaceFounder.Core.Model.commitMethod
commit(ledger::BallotBoxController)

Return a commit for the ballotbox ledger.

source
PeaceFounder.Core.Model.commitMethod
commit(station::PollingStation, uuid::UUID)::Commit

Return a ballotbox commit.

source
PeaceFounder.Core.Model.generatorMethod
generator(ledger::BallotBoxController)

Return a relative generator which members use to sign votes anchored by the proposal.

source
PeaceFounder.Core.Model.indexMethod
index(ledger::BallotBoxController)

Return the current index of the ledger. See also length.

source
PeaceFounder.Core.Model.isbindingMethod
isbinding(vote::Vote, ack::CastAck, hasher)

Check whether acknowledgment is bound to the provided vote.

source
PeaceFounder.Core.Model.receiptMethod
receipt(ledger::BallotBoxController, index::Int)::CastReceipt

Return a receipt for a ledger element.

source
PeaceFounder.Core.Model.receiptMethod
receipt(station::PollingStation, uuid::UUID, N::Int)::CastReceipt

Return a receipt for a record with index N at ballotbox with uuid.

source
PeaceFounder.Core.Model.seedMethod
seed(ledger::BallotBoxController)::Union{Digest, Nothing}

Return a random selected seed used in the voting.

source
PeaceFounder.Core.Model.tallyMethod
tally(station::PollingStation, uuid::UUID)

Compute a tally from ledger records a ballotbox with uuid.

source
PeaceFounder.Core.Model.uuidMethod
uuid(ledger::BallotBoxController)

Return a UUID of the proposal.

source
PeaceFounder.Core.Model.votersMethod
voters(ledger::BallotBoxController)

Return a list of member pseudonyms with which members authetificate their votes.

source
PeaceFounder.Server.Controllers.ack_castMethod
ack_cast(ledger::BallotBoxController, index::Int)::CastAck

Compute an acknowledgment for record inclusion at index.

source
PeaceFounder.Server.Controllers.ack_castMethod
ack_cast(station::PollingStation, uuid::UUID, N::Int)::CastAck

Return inclusion proof with receipt and current tree commit for a leaf at index N and ballotbox with uuid.

source
PeaceFounder.Server.Controllers.ack_leafMethod
ack_leaf(ledger::BallotBoxController, index::Int)::AckInclusion

Compute an inclusion proof ::AckInclusion for record element at given index.

source
PeaceFounder.Server.Controllers.ack_leafMethod
ack_leaf(station::PollingStation, uuid::UUID, N::Int)::AckInclusion

Return history tree inclusion proof for a tree leaf at index N in ballotbox with uuid.

source
PeaceFounder.Server.Controllers.ack_rootMethod
ack_root(ledger::BallotBoxController, index::Int)::AckConsistency

Compute a history tree consistency proof at index.

source
PeaceFounder.Server.Controllers.ack_rootMethod
ack_root(station::PollingStation, uuid::UUID, N::Int)::AckConsistency

Return history tree consitency proof tree root at index N in ballotbox with uuid.

source
PeaceFounder.Server.Controllers.commit!Method
commit!(ledger::BallotBoxController[, timestamp::DataTime], signer::Signer; with_tally=nothing)

Flushes ballotbox ledger's queue and creates a commit for a current ballotbox ledger state with provided timestamp and signer. A keyword argument with_tally has three values true|false to include or exclude a tally from a commited state and nothing which uses a previous commit preference.

source
PeaceFounder.Server.Controllers.commit!Method
commit!(station::PollingStation, uuid::UUID, collector::Signer; with_tally = nothing)

Select a ballotbox with provided uuid and commit it's state with collector.

source
PeaceFounder.Server.Controllers.commit_indexMethod
commit_index(ledger::BallotBoxController)::Union{Index, Nothing}

Index at which commit is issued. See also length and index

source
PeaceFounder.Server.Controllers.commit_stateMethod
commit_state(ledger::BallotBoxController)

Return a committed state for a ballotbox ledger.

source
PeaceFounder.Server.Controllers.init!Method
init!(station::PollingStation, proposal::Proposal, voters::Set{Pseudonym}[, collector::Pseudonym])

Creates a new ballotbox for given proposal with provided member pseudonyms at a relative generator anchored in the proposal. A collector is optional and provided only when it differs from one specified in the proposal.

source
PeaceFounder.Server.Controllers.ledgerMethod
ledger(ballotbox::BallotBoxController)::Vector{CastRecord}

Return all records from a ballotbox ledger.

source
PeaceFounder.Server.Controllers.ledgerMethod
ledger(station::PollingStation, uuid::UUID)::Vector{CastRecord}

Return a vector of records from a ballotbox with uuid.

source
PeaceFounder.Server.Controllers.record!Method
record!(ledger::BallotBoxController, record::CastRecord)

Check the vote in the record for validity and include that in the ledger directly bypassing queue. This method is useful for replaying and debugging ballotbox ledger state changes. See also record!

source
PeaceFounder.Server.Controllers.record!Method
record!(ledger::BallotBoxController, vote::Vote)

Check the vote for validity and pushes it to the queue. Returns an index N at which the vote will be recorded in the ledger. See also push!

source
PeaceFounder.Server.Controllers.record!Method
record!(station::PollingStation, uuid::UUID, vote::Vote)::Int

Records a vote in a ballotbox with provided proposal UUID. Throws an error if a ballotbox can't be found.

source
PeaceFounder.Server.Controllers.record!Method
record!(station::PollingStation, uuid::UUID, vote::Vote)::Int

Record a vote in a ballotbox found by proposal diggest stored in the vote. Throws an error if a ballotbox can't be found.

source
PeaceFounder.Server.Controllers.reset_tree!Method
reset_tree!(ledger::BallotBoxController)

Recompute history tree root and cache from the elements in the ledger. This is a useful for loading the ledger all at once.

source
PeaceFounder.Server.Controllers.set_seed!Method
set_seed!(ledger::BallotBoxController, seed::Digest)

Set's a seed of the ballotbox.

source
PeaceFounder.Server.Controllers.set_seed!Method
set_seed!(station::PollingStation, uuid::UUID, seed::Digest)

Sets a seed for a ballotbox with provided uuid.

source
PeaceFounder.Server.Controllers.spineMethod
spine(ledger::BallotBoxController)::Vector{Digest}

Return a history tree leaf vector.

source
PeaceFounder.Server.Controllers.spineMethod
spine(station::PollingStation, uuid::UUID)::Vector{Digest}

Return a leaf vector for a ballotbox with proposal uuid.

source
PeaceFounder.Server.Controllers.validateMethod
validate(ledger::BallotBoxController, vote::Vote)

Check that vote can be included in the ballotbox. Is well formed, signed by a member pseudonym and cryptographic signature is valid. Raises error if either of checks fail.

source
diff --git a/dev/index.html b/dev/index.html index 383251a..f74980a 100644 --- a/dev/index.html +++ b/dev/index.html @@ -1,2 +1,2 @@ -PeaceFounder.jl · PeaceFounder.jl

PeaceFounder.jl

PeaceFounder is a centralised E2E verifiable e-voting system that leverages pseudonym braiding and history trees. The immutability of the bulletin board is maintained replication-free by voter’s client devices with locally stored consistency-proof chains. Meanwhile, pseudonym braiding done via an exponentiation mix before the vote allows anonymisation to be transactional with a single braider at a time. In contrast to existing E2E verifiable e-voting systems, it is much easier to deploy as the system is fully centralised, free from threshold decryption ceremonies, trusted setup phases and bulletin board replication. Furthermore, the body of a vote is signed with a braided pseudonym, enabling unlimited ballot types.

Introduction

everal end-to-end (E2E) verifiable e-voting systems exist, such as Helios, Scytl, Belenios, ElectionGuard, Estonia's system, and Verificatum, with many available under open-source licences. They all encrypt and mix votes through a re-encryption shuffle and use a threshold decryption ceremony. This allows voters to track their encrypted votes and the public to verify the final tally. However, it depends on the integrity of the bulletin board and the coordination of the threshold decryption ceremony, presenting challenges for smaller communities and organisations.

To make a point, let's consider a Helios voting system. The vote in Helios is stored in a group element, encrypted and signed by a digital signature provider, and then submitted to the bulletin board. When the vote closes, votes go through the reencryption shuffle and are decrypted in the threshold decryption ceremony. Voters can ensure that their vote has been counted by finding their encrypted vote within the list of inputs of the mix cascade. Furthermore, everyone can verify the final tally by counting the decrypted votes and verifying supplemented zero-knowledge proofs without compromising privacy. In this way, the integrity of the election result can be assured.

However, issues like forced abstention and potential vote substitution of unverified votes can happen if authorities are corrupt and auditing/monitoring does not occur. Publishing vote-casting signatures can alleviate many of those issues, but that violates participation privacy. The threshold decryption ceremony further compounds the system's complexity; if more than a few are corrupt, votes can remain encrypted, while a low threshold risks privacy breaches. These factors, coupled with the technical intricacies of deployment, make Helios less feasible for small to medium-sized communities, leading to a preference for simpler black box systems to prevent questions from being asked, which can foster trust at the expense of trustworthiness.

A significant improvement over Helios is the Selene system, which offers a voter-assigned tracking number and shows their votes next to them after the vote. Recent usability studies with Selene have demonstrated that voters appreciate the ability to verify their vote in plaintext. This allows them to discard their trust in advanced cryptography as they can see how their vote is counted. As the tracking number is not published before the vote and is deniable, it is also coercion-resistant. In addition to clever cryptography, it can also detect malware interference. However, the threshold decryption ceremony still needs to be deployed along with the bulletin board and thus would generally suit only state-like elections.

Haenni & Spycher proposed a system using exponentiation mixes to anonymise voters' pseudonyms, eliminating the need for a threshold decryption ceremony. However, the benefits of such a system have yet to be reaped as it requires a trusted bulletin board that does not discard unfavourable votes; thus, deployment of such a system needs to be distributed and hence offers minor deployment improvements over Helios. Furthermore, over 13 years, a single open-source system has yet to be implemented.

The innovative approach by PeaceFounder combines pseudonym braiding developed by Haenni & Spycher with a history trees-enabled bulletin board (Crosby & Wallach). When voters cast their vote, their devices receive inclusion proof of the vote, which can later be verified to be binding to the tally with consistency proof. By having only a few voters who request their device to check the proofs, the immutability of the bulletin board is guaranteed. Thus, once the server has assured that the vote is recorded, there is no way for it to be removed. This allows the system to be fully centralised and, thus, makes it easy to self-host.

However, such a system poses many challenges compared to the orthodox approach. To protect against a corrupt server that discards unfavourable votes, voters must have the option to route the vote through proxy/monitor, which adds a challenge with coercion/bribery. To reap the benefits of braiding pseudonyms with any other community/organisation worldwide, the voters must be registered long before the vote starts, which would produce a bad user experience. Therefore, disengaging anonymisation from voting requires long-standing accounts, which poses an issue for continuous member registration and termination; on top of that, the votes need to be delivered over an anonymous channel not to be traceable by a corrupt authority. All of them are addressed with the PeaceFounder project in innovative ways.

Demo

An 8-minute YouTube demonstration is available here:

IMAGE ALT TEXT HERE

References

  • Rolf Haenni and Oliver Spycher. Secure internet voting on limited devices with anonymized DSA public keys. 2011
  • Scott A. Crosby and Dan S. Wallach. Efficient data structures for tamper-evident logging. 2009
  • Björn Terelius and Douglas Wikström. Proofs of restricted shuffles. 2010.
+PeaceFounder.jl · PeaceFounder.jl

PeaceFounder.jl

PeaceFounder is a centralised E2E verifiable e-voting system that leverages pseudonym braiding and history trees. The immutability of the bulletin board is maintained replication-free by voter’s client devices with locally stored consistency-proof chains. Meanwhile, pseudonym braiding done via an exponentiation mix before the vote allows anonymisation to be transactional with a single braider at a time. In contrast to existing E2E verifiable e-voting systems, it is much easier to deploy as the system is fully centralised, free from threshold decryption ceremonies, trusted setup phases and bulletin board replication. Furthermore, the body of a vote is signed with a braided pseudonym, enabling unlimited ballot types.

Introduction

everal end-to-end (E2E) verifiable e-voting systems exist, such as Helios, Scytl, Belenios, ElectionGuard, Estonia's system, and Verificatum, with many available under open-source licences. They all encrypt and mix votes through a re-encryption shuffle and use a threshold decryption ceremony. This allows voters to track their encrypted votes and the public to verify the final tally. However, it depends on the integrity of the bulletin board and the coordination of the threshold decryption ceremony, presenting challenges for smaller communities and organisations.

To make a point, let's consider a Helios voting system. The vote in Helios is stored in a group element, encrypted and signed by a digital signature provider, and then submitted to the bulletin board. When the vote closes, votes go through the reencryption shuffle and are decrypted in the threshold decryption ceremony. Voters can ensure that their vote has been counted by finding their encrypted vote within the list of inputs of the mix cascade. Furthermore, everyone can verify the final tally by counting the decrypted votes and verifying supplemented zero-knowledge proofs without compromising privacy. In this way, the integrity of the election result can be assured.

However, issues like forced abstention and potential vote substitution of unverified votes can happen if authorities are corrupt and auditing/monitoring does not occur. Publishing vote-casting signatures can alleviate many of those issues, but that violates participation privacy. The threshold decryption ceremony further compounds the system's complexity; if more than a few are corrupt, votes can remain encrypted, while a low threshold risks privacy breaches. These factors, coupled with the technical intricacies of deployment, make Helios less feasible for small to medium-sized communities, leading to a preference for simpler black box systems to prevent questions from being asked, which can foster trust at the expense of trustworthiness.

A significant improvement over Helios is the Selene system, which offers a voter-assigned tracking number and shows their votes next to them after the vote. Recent usability studies with Selene have demonstrated that voters appreciate the ability to verify their vote in plaintext. This allows them to discard their trust in advanced cryptography as they can see how their vote is counted. As the tracking number is not published before the vote and is deniable, it is also coercion-resistant. In addition to clever cryptography, it can also detect malware interference. However, the threshold decryption ceremony still needs to be deployed along with the bulletin board and thus would generally suit only state-like elections.

Haenni & Spycher proposed a system using exponentiation mixes to anonymise voters' pseudonyms, eliminating the need for a threshold decryption ceremony. However, the benefits of such a system have yet to be reaped as it requires a trusted bulletin board that does not discard unfavourable votes; thus, deployment of such a system needs to be distributed and hence offers minor deployment improvements over Helios. Furthermore, over 13 years, a single open-source system has yet to be implemented.

The innovative approach by PeaceFounder combines pseudonym braiding developed by Haenni & Spycher with a history trees-enabled bulletin board (Crosby & Wallach). When voters cast their vote, their devices receive inclusion proof of the vote, which can later be verified to be binding to the tally with consistency proof. By having only a few voters who request their device to check the proofs, the immutability of the bulletin board is guaranteed. Thus, once the server has assured that the vote is recorded, there is no way for it to be removed. This allows the system to be fully centralised and, thus, makes it easy to self-host.

However, such a system poses many challenges compared to the orthodox approach. To protect against a corrupt server that discards unfavourable votes, voters must have the option to route the vote through proxy/monitor, which adds a challenge with coercion/bribery. To reap the benefits of braiding pseudonyms with any other community/organisation worldwide, the voters must be registered long before the vote starts, which would produce a bad user experience. Therefore, disengaging anonymisation from voting requires long-standing accounts, which poses an issue for continuous member registration and termination; on top of that, the votes need to be delivered over an anonymous channel not to be traceable by a corrupt authority. All of them are addressed with the PeaceFounder project in innovative ways.

Demo

An 8-minute YouTube demonstration is available here:

IMAGE ALT TEXT HERE

References

  • Rolf Haenni and Oliver Spycher. Secure internet voting on limited devices with anonymized DSA public keys. 2011
  • Scott A. Crosby and Dan S. Wallach. Efficient data structures for tamper-evident logging. 2009
  • Björn Terelius and Douglas Wikström. Proofs of restricted shuffles. 2010.
diff --git a/dev/model/index.html b/dev/model/index.html index cbc16a0..3fe318c 100644 --- a/dev/model/index.html +++ b/dev/model/index.html @@ -2,40 +2,40 @@ PeaceFounder.Core.Model · PeaceFounder.jl

PeaceFounder.Core.Model

Primitives

PeaceFounder.Core.Model.CryptoSpecType
struct CryptoSpec
     hasher::HashSpec
     group::GroupSpec
     generator::Generator
-end

Specification of cryptographic parameters which are used for public key cryptography, message hashing and authetification codes.

source
PeaceFounder.Core.Model.DigestType
struct Digest
+end

Specification of cryptographic parameters which are used for public key cryptography, message hashing and authetification codes.

source
PeaceFounder.Core.Model.GeneratorType
struct Generator
     data::Vector{UInt8}
-end

Datatype which stores cryptogrpahic group point in standart octet form intended to be used as a base. See also Pseudonym.

source
PeaceFounder.Core.Model.HMACType
struct HMAC
+end

Datatype which stores cryptogrpahic group point in standart octet form intended to be used as a base. See also Pseudonym.

source
PeaceFounder.Core.Model.SignerType
struct Signer
     spec::CryptoSpec
     pbkey::Pseudonym
     key::BigInt
-end

A signer type. See a method generate(Signer, spec) for initialization.

Interface: pseudonym, id, sign, seal, approve

source
PeaceFounder.Core.Model.digestMethod
digest(message::Vector{UInt8}, hasher::HashSpec)::Digest
-digest(document, spec) = digest(canonicalize(message)::Vector{UInt8}, hasher(spec)::HashSpec)

Return a resulting digest applying hasher on the given message. When message is not octet string a canonicalize method is applied first.

source
PeaceFounder.Core.Model.digestMethod
digest(bytes::Vector{UInt8}, hasher::HashSpec)::Digest
-digest(x, spec) = digest(canonicalize(x)::Vector{UInt8}, hasher(spec)::HashSpec)

Compute a hash digest. When input is not in bytes the canonicalize method is applied first.

source
PeaceFounder.Core.Model.sealMethod
seal(message::Vector{UInt8}[, generator::Generator], signer::Signer)::Seal

Sign a bytestring message with signer's private key and specification and return a signature as a Seal. When generator is provided it is used as a base for the signature. See also sign.

source
PeaceFounder.Core.Model.signMethod
sign(digest::Digest[, generator::Generator], signer::Signer)::Signature

Sign a digest as an integer with signer's private key and specification. This method avoids running hashing twice when that is done externally. When generator is provided it is used as a base for the signature.

source
PeaceFounder.Core.Model.signMethod
sign(message::Vector{UInt8}[, generator::Generator], signer::Signer)::Signature

Sign a bytestring message with signer's private key and specification. When generator is provided it is used as a base for the signature.

source
PeaceFounder.Core.Model.canonicalizeFunction

ToDo: a well specified encoding is essential here. Binary tree encoding may suffice here. More fancy approach would be to use a DER encoding. Meanwhile JSON shall be used.

source
PeaceFounder.Core.Model.pseudonymFunction
pseudonym(signer::Signer, [generator])::Pseudonym

Return a pseudonym of a signer at a given relative generator. If generator is not passed returns identity pseudonym. (See also id)


pseudonym(seal::Seal)::Pseudonym

Return a pseudonym of a seal. Note that it is not equal to identity when the signature is issued on a relative generator.


pseudonym(vote::Vote)::Pseudonym

Return a pseudonym used to seal the vote.

source
PeaceFounder.Core.Model.idFunction
id(document)::Pseudonym

Return identity pseudonym of a document issuer.


id(signer)::Pseudonym

Return identity pseudonym of a signer.

source
PeaceFounder.Core.Model.verifyFunction
verify(message, seal::Seal, [generator::Generator], crypto::CryptoSpec)::Bool
-verify(message, pk::Pseudonym, sig::Signature, [generator::Generator], crypto::CryptoSpec)::Bool

Verify the cryptographic signature of the message returning true if valid. An optional generator can be given when signature is issued on a relative generator differing from a base specification crypto.


verify(document[, generator::Generator], crypto::CryptoSpec)::Bool

Verify a cryptographic signature of the document returning true if valid.


verify(braidwork::BraidReceipt, crypto::CryptoSpec)::Bool

Verify a braider issued cryptographic signature for the braidwork and a zero knowledge proofs. Returns true if both checks succeed.

source

BraidChain

PeaceFounder.Core.Model.digestMethod
digest(message::Vector{UInt8}, hasher::HashSpec)::Digest
+digest(document, spec) = digest(canonicalize(message)::Vector{UInt8}, hasher(spec)::HashSpec)

Return a resulting digest applying hasher on the given message. When message is not octet string a canonicalize method is applied first.

source
PeaceFounder.Core.Model.digestMethod
digest(bytes::Vector{UInt8}, hasher::HashSpec)::Digest
+digest(x, spec) = digest(canonicalize(x)::Vector{UInt8}, hasher(spec)::HashSpec)

Compute a hash digest. When input is not in bytes the canonicalize method is applied first.

source
PeaceFounder.Core.Model.sealMethod
seal(message::Vector{UInt8}[, generator::Generator], signer::Signer)::Seal

Sign a bytestring message with signer's private key and specification and return a signature as a Seal. When generator is provided it is used as a base for the signature. See also sign.

source
PeaceFounder.Core.Model.signMethod
sign(digest::Digest[, generator::Generator], signer::Signer)::Signature

Sign a digest as an integer with signer's private key and specification. This method avoids running hashing twice when that is done externally. When generator is provided it is used as a base for the signature.

source
PeaceFounder.Core.Model.signMethod
sign(message::Vector{UInt8}[, generator::Generator], signer::Signer)::Signature

Sign a bytestring message with signer's private key and specification. When generator is provided it is used as a base for the signature.

source
PeaceFounder.Core.Model.canonicalizeFunction

ToDo: a well specified encoding is essential here. Binary tree encoding may suffice here. More fancy approach would be to use a DER encoding. Meanwhile JSON shall be used.

source
PeaceFounder.Core.Model.pseudonymFunction
pseudonym(signer::Signer, [generator])::Pseudonym

Return a pseudonym of a signer at a given relative generator. If generator is not passed returns identity pseudonym. (See also id)


pseudonym(seal::Seal)::Pseudonym

Return a pseudonym of a seal. Note that it is not equal to identity when the signature is issued on a relative generator.


pseudonym(vote::Vote)::Pseudonym

Return a pseudonym used to seal the vote.

source
PeaceFounder.Core.Model.idFunction
id(document)::Pseudonym

Return identity pseudonym of a document issuer.


id(signer)::Pseudonym

Return identity pseudonym of a signer.

source
PeaceFounder.Core.Model.verifyFunction
verify(message, seal::Seal, [generator::Generator], crypto::CryptoSpec)::Bool
+verify(message, pk::Pseudonym, sig::Signature, [generator::Generator], crypto::CryptoSpec)::Bool

Verify the cryptographic signature of the message returning true if valid. An optional generator can be given when signature is issued on a relative generator differing from a base specification crypto.


verify(document[, generator::Generator], crypto::CryptoSpec)::Bool

Verify a cryptographic signature of the document returning true if valid.


verify(braidwork::BraidReceipt, crypto::CryptoSpec)::Bool

Verify a braider issued cryptographic signature for the braidwork and a zero knowledge proofs. Returns true if both checks succeed.

source

BraidChain

PeaceFounder.Core.Model.DemeSpecType
struct DemeSpec <: Transaction
     uuid::UUID
     title::String
     crypto::CryptoSpec
@@ -47,33 +47,33 @@
     collector::Pseudonym
     timestamp::Union{DateTime, Nothing} = nothing
     signature::Union{Signature, Nothing} = nothing
-end

Represents a deme configuration parameters issued by the guardian.

  • uuid::UUID an unique random generated community identifier;
  • title::String a community name with which deme is represented;
  • crypto::CryptoSpec cryptographic parameters for the deme;
  • guardian::Pseudonym an issuer for this demespec file. Has authorithy to set a roster:
    • recorder::Pseudonym an authorithy which has rights to add new transactions and is responsable for braidchain's ledger integrity. Issues Commit{ChainState};
    • registrar::Pseudonym an authorithy which has rights to authorize new admissions to the deme. See Admission and Membership;
    • braider::Pseudonym an authorithy which can do a legitimate braid jobs for other demes. See BraidReceipt;
    • proposer::Pseudonym an authorithy which has rights to issue a proposals for the braidchain. See Proposal;
    • collector::Pseudonym an authorithy which is repsonsable for collecting votes for proposals. This is also recorded in the proposal itself.
  • timestamp::Union{DateTime, Nothing} time when signature is being issued;
  • signature::Union{Signature, Nothing} a guardian issued signature.
source
PeaceFounder.Core.Model.MembershipType
struct Membership <: Transaction
+end

Represents a deme configuration parameters issued by the guardian.

  • uuid::UUID an unique random generated community identifier;
  • title::String a community name with which deme is represented;
  • crypto::CryptoSpec cryptographic parameters for the deme;
  • guardian::Pseudonym an issuer for this demespec file. Has authorithy to set a roster:
    • recorder::Pseudonym an authorithy which has rights to add new transactions and is responsable for braidchain's ledger integrity. Issues Commit{ChainState};
    • registrar::Pseudonym an authorithy which has rights to authorize new admissions to the deme. See Admission and Membership;
    • braider::Pseudonym an authorithy which can do a legitimate braid jobs for other demes. See BraidReceipt;
    • proposer::Pseudonym an authorithy which has rights to issue a proposals for the braidchain. See Proposal;
    • collector::Pseudonym an authorithy which is repsonsable for collecting votes for proposals. This is also recorded in the proposal itself.
  • timestamp::Union{DateTime, Nothing} time when signature is being issued;
  • signature::Union{Signature, Nothing} a guardian issued signature.
source
PeaceFounder.Core.Model.MembershipType
struct Membership <: Transaction
     admission::Admission
     generator::Generator
     pseudonym::Pseudonym
     approval::Union{Signature, Nothing} 
-end

A new member certificate which rolls in (anouances) it's pseudonym at current generator signed with identity pseudonym certified with admission certificate issued by registrar. This two step process is necessary as a checkpoint in situations when braidchain ledger get's locked during a new member resgistration procedure.

source
PeaceFounder.Core.Model.TicketIDType
struct TicketID
+end

A new member certificate which rolls in (anouances) it's pseudonym at current generator signed with identity pseudonym certified with admission certificate issued by registrar. This two step process is necessary as a checkpoint in situations when braidchain ledger get's locked during a new member resgistration procedure.

source
PeaceFounder.Core.Model.TicketIDType
struct TicketID
     id::Vector{UInt8}
-end

Represents a unique identifier for which a recruit tooken is issued. In case of necessity id can contain a full document, for instance, registration form, proof of identity and etc. In case a privacy is an issue the id can contain a unique identifier which can be matched to an identity in an external database.

source
PeaceFounder.Core.Model.approveMethod
approve(x::T, signer::Signer)::T

Cryptographically sign a document x::T and returns a signed document with the same type. To check whether a document is signed see issuer method.

source
PeaceFounder.Core.Model.membersMethod
members(ledger::BraidChainLedger[, index::Int])::Set{Pseudonym}

Return a set of member pseudonyms at relative generator at braidchain ledger row index. If index is omitted return a current state value.

source
PeaceFounder.Core.Model.BraidReceiptType
struct BraidReceipt <: Transaction
+end

Represents a unique identifier for which a recruit tooken is issued. In case of necessity id can contain a full document, for instance, registration form, proof of identity and etc. In case a privacy is an issue the id can contain a unique identifier which can be matched to an identity in an external database.

source
PeaceFounder.Core.Model.approveMethod
approve(x::T, signer::Signer)::T

Cryptographically sign a document x::T and returns a signed document with the same type. To check whether a document is signed see issuer method.

source
PeaceFounder.Core.Model.membersMethod
members(ledger::BraidChainLedger[, index::Int])::Set{Pseudonym}

Return a set of member pseudonyms at relative generator at braidchain ledger row index. If index is omitted return a current state value.

source
PeaceFounder.Core.Model.BraidReceiptType
struct BraidReceipt <: Transaction
     braid::Simulator
     producer::DemeSpec
     approval::Union{Seal, Nothing}
-end

Represents a braider's computation which is supported with zero knowledge proof of shuffle and decryption assuring it's corectness stored in a braid field; producer denotes a deme where the braid is made. To assert latter the the braider signs the braidwork and stores that in the aproval field. See a braid method.

Interface: approve, verify, input_generator, input_members, output_generator, output_members

source
PeaceFounder.Core.Model.approveMethod
approve(braid::BraidReceipt, spec::DemeSpec, braider::Signer)

Sign a braidwork with a braider. Throws an error if braider is not in the producer demespec.

source
PeaceFounder.Core.Model.braidMethod
braid(generator::Generator, members::Union{Vector{Pseudonym}, Set{Pseudonym}}, consumer::DemeSpec, producer::DemeSpec; verifier = (g) -> ProtocolSpec(; g))

Selects a private exponent x at random and computes a new generator $g' = g^x$ and $member_i'=member_i^x$ returns the latter in a sorted order and provides a zero knowledge proof that all operations have been performed honestly. In partucular, not including/droping new member pseudonyms in the process. consumer attributes are necessary to interepret generator and pseudonym group elements with which the computation is performed.

By default a Verificatum compatable verifier is used for performing reencryption proof of shuffle

A verifier can be configured with a keyword argument. By default a Verificatum compatable verifier for a proof of shuffle is used.

source
PeaceFounder.Core.Model.verifyMethod
verify(braid::BraidReceipt, crypto::CryptoSpec)

Verifies a braid approval and then it's zero knowledge proofs. A crypto argument is provided to avoid downgrading attacks.

source

Ballot Box

PeaceFounder.Core.Model.approveMethod
approve(braid::BraidReceipt, spec::DemeSpec, braider::Signer)

Sign a braidwork with a braider. Throws an error if braider is not in the producer demespec.

source
PeaceFounder.Core.Model.braidMethod
braid(generator::Generator, members::Union{Vector{Pseudonym}, Set{Pseudonym}}, consumer::DemeSpec, producer::DemeSpec; verifier = (g) -> ProtocolSpec(; g))

Selects a private exponent x at random and computes a new generator $g' = g^x$ and $member_i'=member_i^x$ returns the latter in a sorted order and provides a zero knowledge proof that all operations have been performed honestly. In partucular, not including/droping new member pseudonyms in the process. consumer attributes are necessary to interepret generator and pseudonym group elements with which the computation is performed.

By default a Verificatum compatable verifier is used for performing reencryption proof of shuffle

A verifier can be configured with a keyword argument. By default a Verificatum compatable verifier for a proof of shuffle is used.

source
PeaceFounder.Core.Model.verifyMethod
verify(braid::BraidReceipt, crypto::CryptoSpec)

Verifies a braid approval and then it's zero knowledge proofs. A crypto argument is provided to avoid downgrading attacks.

source

Ballot Box

PeaceFounder.Core.Model.BallotBoxStateType
struct BallotBoxState
     proposal::Digest
     seed::Digest
     index::Int
     root::Digest
     tally::Union{Nothing, Tally} 
     view::Union{Nothing, BitVector} # 
-end

Represents a public ballot box state. Contains an immutable proposal and seed digest; a current ledger index, history tree root. When ellections end a tally is included in the state and a view is added listing all counted votes. Note that the view attribute is important for a client to know whether it's key have leaked and somone lese havbe superseeded it's vote by revoting.

source
PeaceFounder.Core.Model.CastReceiptType
struct CastReceipt
+end

Represents a public ballot box state. Contains an immutable proposal and seed digest; a current ledger index, history tree root. When ellections end a tally is included in the state and a view is added listing all counted votes. Note that the view attribute is important for a client to know whether it's key have leaked and somone lese havbe superseeded it's vote by revoting.

source
PeaceFounder.Core.Model.CastReceiptType
struct CastReceipt
     vote::Digest
     timestamp::DateTime
-end

Represents a ballotbox ledger receipt which is hashed for a history tree. It's sole purpose is to assure voters that their vote is included in the ledger while also adding additional metadata as timestamp and. In contrast to CastRecord it does not reveal how voter have voted thus can be published during ellections without violating fairness property. For some situations it may be useful to extend the time until the votes are published as that can disincentivice coercers and bribers as they would not know whether their coerced vote have been superseeded in revoting. See receipt method for it's construction from a CastRecord.

Note that a blind signature could be commited as H(signature|H(vote)) to avoid tagging the use of pseudonym during ellections while collector could issue only a one blind signature for a voter. Note that members whoose private key could have been stolen could not obtain a valid signature for participation and that could be a good thing!

source
PeaceFounder.Core.Model.CastRecordType
struct CastRecord
+end

Represents a ballotbox ledger receipt which is hashed for a history tree. It's sole purpose is to assure voters that their vote is included in the ledger while also adding additional metadata as timestamp and. In contrast to CastRecord it does not reveal how voter have voted thus can be published during ellections without violating fairness property. For some situations it may be useful to extend the time until the votes are published as that can disincentivice coercers and bribers as they would not know whether their coerced vote have been superseeded in revoting. See receipt method for it's construction from a CastRecord.

Note that a blind signature could be commited as H(signature|H(vote)) to avoid tagging the use of pseudonym during ellections while collector could issue only a one blind signature for a voter. Note that members whoose private key could have been stolen could not obtain a valid signature for participation and that could be a good thing!

source
PeaceFounder.Core.Model.CastRecordType
struct CastRecord
     vote::Vote
     timestamp::DateTime
-end

Represents a ballotbox ledger record. Adds a timestamp when the vote have been recorded. In future, the record will also contain a blind signature with which members could prove to everyone that they had cast their vote without revealing the link to the vote.

source
PeaceFounder.Core.Model.ProposalType
struct Proposal <: Transaction 
+end

Represents a ballotbox ledger record. Adds a timestamp when the vote have been recorded. In future, the record will also contain a blind signature with which members could prove to everyone that they had cast their vote without revealing the link to the vote.

source
PeaceFounder.Core.Model.ProposalType
struct Proposal <: Transaction 
     uuid::UUID
     summary::String
     description::String
@@ -83,23 +83,23 @@
     collector::Union{Pseudonym, Nothing} # 
     anchor::Union{ChainState, Nothing}
     approval::Union{Seal, Nothing} 
-end

Represents a proposal for a ballot specyfing voting window, unique identifier, summary, description. Set's the collector identity which collects votes and issues vote inclusion receipts and is responsable for maintaining the ledger's integrity. The proposal also includes an anchor which sets a relative generator with which members vote anonymously. To be considered valid is signed by proposer authorizing vote to take place.

source
PeaceFounder.Core.Model.SelectionType
struct Selection
+end

Represents a proposal for a ballot specyfing voting window, unique identifier, summary, description. Set's the collector identity which collects votes and issues vote inclusion receipts and is responsable for maintaining the ledger's integrity. The proposal also includes an anchor which sets a relative generator with which members vote anonymously. To be considered valid is signed by proposer authorizing vote to take place.

source
PeaceFounder.Core.Model.VoteType
struct Vote
     proposal::Digest
     seed::Digest
     selection::Selection
     seq::Int
     approval::Union{Seal, Nothing} 
-end

Represents a vote for a proposal issued by a member. The proposal is stored as hash digest ensuring that member have voted on an untampered proposal. seed contains a randon string issued by collector at the moment when a vote starts to eliminate early voting / shortening a time at which coercers could act uppon. selection contians voter's preference;

seq is a serquence number counting a number of votes at which vote have been approved for a given proposal. It starts at 1 and is increased by one for every single signature made on the proposal. This is an important measure which allows to detect possible leakage of a member's private key. Also provides means for revoting ensuring that latest vote get's counted.

The vote is considered valid when it is sealed by a member's private key at a relative generator stored in the proposal.

source
HistoryTrees.rootMethod
root(state::BallotBoxState)

Return a history tree root for a current ballotbox ledger state.

source
PeaceFounder.Core.Model.isconsistentMethod
isconsistent(selection::Selection, ballot::Ballot)

Verifies that voter's selection is consistent with ballot form. For instance, whether selection is withing the range of ballot options.

source
PeaceFounder.Core.Model.stateFunction
state(ledger::BallotBoxLedger; seed::Digest, root::Digest = root(ledger), with_tally::Union{Nothing, Bool} = nothing)::BallotBoxState

Return a state metadata for ballotbox ledger.

source
PeaceFounder.Core.Model.tallyMethod
tally(ballot::Ballot, ballots::AbstractVector{Selection})::Tally

Count ballots, check that they are filled consistently and return a final tally.

source
PeaceFounder.Core.Model.uuidMethod
uuid(proposal::Proposal)::UUID

UUID for a proposal. Issued by proposer and it's purpose is to croslink to an external system durring the proposal dreafting stage.

source
PeaceFounder.Core.Model.voteMethod
vote(proposal::Proposal, seed::Digest, selection::Selection, member::Signer; seq = 1)

Issue a vote on a proposal and provided collector seed for a member's selection.

source

Auditing

PeaceFounder.Core.ProtocolSchema

PeaceFounder.Core.ProtocolSchema.AckConsistencyType
struct AckConsistency{T}
+end

Represents a vote for a proposal issued by a member. The proposal is stored as hash digest ensuring that member have voted on an untampered proposal. seed contains a randon string issued by collector at the moment when a vote starts to eliminate early voting / shortening a time at which coercers could act uppon. selection contians voter's preference;

seq is a serquence number counting a number of votes at which vote have been approved for a given proposal. It starts at 1 and is increased by one for every single signature made on the proposal. This is an important measure which allows to detect possible leakage of a member's private key. Also provides means for revoting ensuring that latest vote get's counted.

The vote is considered valid when it is sealed by a member's private key at a relative generator stored in the proposal.

source
HistoryTrees.rootMethod
root(state::BallotBoxState)

Return a history tree root for a current ballotbox ledger state.

source
PeaceFounder.Core.Model.isconsistentMethod
isconsistent(selection::Selection, ballot::Ballot)

Verifies that voter's selection is consistent with ballot form. For instance, whether selection is withing the range of ballot options.

source
PeaceFounder.Core.Model.stateFunction
state(ledger::BallotBoxLedger; seed::Digest, root::Digest = root(ledger), with_tally::Union{Nothing, Bool} = nothing)::BallotBoxState

Return a state metadata for ballotbox ledger.

source
PeaceFounder.Core.Model.tallyMethod
tally(ballot::Ballot, ballots::AbstractVector{Selection})::Tally

Count ballots, check that they are filled consistently and return a final tally.

source
PeaceFounder.Core.Model.uuidMethod
uuid(proposal::Proposal)::UUID

UUID for a proposal. Issued by proposer and it's purpose is to croslink to an external system durring the proposal dreafting stage.

source
PeaceFounder.Core.Model.voteMethod
vote(proposal::Proposal, seed::Digest, selection::Selection, member::Signer; seq = 1)

Issue a vote on a proposal and provided collector seed for a member's selection.

source

Auditing

PeaceFounder.Core.ProtocolSchema

PeaceFounder.Core.ProtocolSchema.AckConsistencyType
struct AckConsistency{T}
     proof::ConsistencyProof
     commit::Commit{T}
-end

Represents an ackknowledgment from the issuer that a root is permanetly included in the ledger. This acknowledgemnt assures that ledger up to index(ack) is included in the current ledger which has has index index(commit(ack)). This is useful in a combination with AckInclusion to privatelly update it's validity rather than asking an explicit element. Also ensures that other elements in the ledger are not being tampered with.

Interface: root, id, issuer, commit, index, verify

source
PeaceFounder.Core.ProtocolSchema.AckInclusionType
struct AckInclusion{T}
+end

Represents an ackknowledgment from the issuer that a root is permanetly included in the ledger. This acknowledgemnt assures that ledger up to index(ack) is included in the current ledger which has has index index(commit(ack)). This is useful in a combination with AckInclusion to privatelly update it's validity rather than asking an explicit element. Also ensures that other elements in the ledger are not being tampered with.

Interface: root, id, issuer, commit, index, verify

source
PeaceFounder.Core.ProtocolSchema.CastAckType
struct CastAck
     receipt::CastReceipt
     ack::AckInclusion{BallotBoxState}
-end

Represents a reply to a voter when a vote have been included in the ballotbox ledger. Contains a receipt and inlcusion acknowledgment. In future would also include a blind signature in the reply for a proof of participation. To receive this reply (with a blind signature in the future) a voter needs to send a vote which is concealed during ellections and thus tagging votes with blind signatures from reply to monitor revoting would be as hard as monitoring the submitted votes.

source
HistoryTrees.leafMethod
leaf(ack::AckInclusion)

Access a leaf diggest for which the acknowledgment is made.

source
HistoryTrees.rootMethod
root(x::AckConsistency)

Access a root diggest for which the acknowledgment is made.

source
PeaceFounder.Core.Model.indexMethod
index(ack::AckConsistency)

Return an index for a root at which the consistency proof is made. To obtain the current ledger index use index(commit(ack)).

source
PeaceFounder.Core.Model.indexMethod
index(ack::AckInclusion)::Int

Return an index at which the leaf is recorded in the ledger. To obtain the current ledger index use index(commit(ack)).

source
PeaceFounder.Core.Model.isbindingMethod
isbinding(receipt::CastReceipt, ack::AckInclusion, hasher::HashSpec)::Bool

Check that cast receipt is binding to received inclusion acknowledgment.

source
PeaceFounder.Core.Model.isbindingMethod
isbinding(record::Transaction, ack::AckInclusion{ChainState}, crypto::CryptoSpec)

A generic method checking whether transaction is included in the braidchain.

source
PeaceFounder.Core.Model.isbindingMethod
isbinding(ack::CastAck, proposal::Proposal, hasher::HashSpec)::Bool

Check that acknowledgment is legitimate meaning that it is issued by a collector listed in the proposal.

source
+end

Represents a reply to a voter when a vote have been included in the ballotbox ledger. Contains a receipt and inlcusion acknowledgment. In future would also include a blind signature in the reply for a proof of participation. To receive this reply (with a blind signature in the future) a voter needs to send a vote which is concealed during ellections and thus tagging votes with blind signatures from reply to monitor revoting would be as hard as monitoring the submitted votes.

source
PeaceFounder.Core.ProtocolSchema.TicketStatusType

struct TicketStatus ticketid::TicketID timestamp::DateTime admission::Union{Nothing, Admission} end

Represents a public state of a ticket. See isadmitted method.

source
HistoryTrees.leafMethod
leaf(ack::AckInclusion)

Access a leaf diggest for which the acknowledgment is made.

source
HistoryTrees.rootMethod
root(x::AckConsistency)

Access a root diggest for which the acknowledgment is made.

source
PeaceFounder.Core.Model.commitMethod
commit(x)

Access a commit of an object x.

source
PeaceFounder.Core.Model.commitMethod
commit(ack::CastAck)

Return a commit from a CastAck.

source
PeaceFounder.Core.Model.indexMethod
index(ack::AckConsistency)

Return an index for a root at which the consistency proof is made. To obtain the current ledger index use index(commit(ack)).

source
PeaceFounder.Core.Model.indexMethod
index(ack::AckInclusion)::Int

Return an index at which the leaf is recorded in the ledger. To obtain the current ledger index use index(commit(ack)).

source
PeaceFounder.Core.Model.isbindingMethod
isbinding(receipt::CastReceipt, ack::AckInclusion, hasher::HashSpec)::Bool

Check that cast receipt is binding to received inclusion acknowledgment.

source
PeaceFounder.Core.Model.isbindingMethod
isbinding(record::Transaction, ack::AckInclusion{ChainState}, crypto::CryptoSpec)

A generic method checking whether transaction is included in the braidchain.

source
PeaceFounder.Core.Model.isbindingMethod
isbinding(ack::CastAck, proposal::Proposal, hasher::HashSpec)::Bool

Check that acknowledgment is legitimate meaning that it is issued by a collector listed in the proposal.

source
PeaceFounder.Core.Model.verifyMethod
verify(ack::CastAck, crypto::CryptoSpec)::Bool

Verify the cast acknowledgment cryptographic signature.

source
PeaceFounder.Core.ProtocolSchema.isadmittedMethod
isadmitted(status::TicketStatus)

Check whether ticket is addmitted.

source
diff --git a/dev/objects.inv b/dev/objects.inv index 921b8a9..9e6fb1c 100644 Binary files a/dev/objects.inv and b/dev/objects.inv differ diff --git a/dev/overview/index.html b/dev/overview/index.html index 32d09ee..dad9438 100644 --- a/dev/overview/index.html +++ b/dev/overview/index.html @@ -8,4 +8,4 @@

The PeaceFounder's bulletin board is a microservice that accepts transactional records and votes. The primary transactional records include member certificates issued in prospective member interaction with the registrar, braid records which recompute pseudonym member list and corresponding relative generator issued by a braider and proposal records announcing a vote issued by a proposer. The system is configured with a guardian issued deme[1] record, which sets cryptographic parameters, and a rooster, which includes the proposer, registrar, and bulletin board authority identities.

The peacefounder bulletin board, proposer, and registrar microservices are internal and can be managed or delegated by a guardian. This separation accommodates customisation for varied political consensus, criteria for proposal submissions to the ballot box, choice of identity provider, and methods for disclosing registrar information to auditors to verify the authenticity of members. To make testing and deployment easier for new organisations, a bundle that includes a registrar, proposer and bulletin board will be available and deployable on a preferred server of choice and will offer web access for a guardian with sane defaults and configuration options.

Member's client devices actively monitor the bulletin board, ensuring the immutability of records by tracking bulletin board commits. This method of oversight is scalable, as members only request a history tree[2] consistency proofs, eliminating the need to replicate the actual bulletin board records. These proofs guarantee the protection of their votes and others, assuring that modifications to records are prevented when fresh entries are appended to the bulletin board. This streamlined approach enables prompt identification of bulletin board dishonesty, whether through removing or altering records or the malicious creation of a counterfeit ledger to exclude undesirable votes from the official tally.

Auditing

Integral to establishing trust, a pivotal role is the presence of an {\bf auditor}. The auditor is a judicial-like entity representing members and is vital for resolving conflicts. Member client devices create local proofs for altered or removed records or the presence of a counterfeit ledger, which are then sent to the auditor. Moreover, if votes aren't delivered, the auditor can act as a proxy, offering evidence that the bulletin board deliberately omitted specific votes. The auditor also ensures the integrity of the bulletin board's records, confirming each vote's eligibility and unlinkability and ensuring one vote per member.

Notably, the auditor can avoid a formal association with the guardian to verify the integrity of a resulting tally, as all relevant data is on the public bulletin board (except for the registration roll). This autonomy allows members the freedom to select their trusted auditors. If there are unresolved disputes with the bulletin board, members can even take on the auditor role and, if necessary, seek to replace the guardian. The system's transparency further allows auditors to cross-check each other's findings, promoting accuracy and preventing the spread of false claims.

The auditor plays a key role in assessing the registrar to confirm the authenticity of its members. The registrar maintains a registration roll, serving as evidence of every member's authenticity. Authenticity verification can be as simple as a trusted third party's digital signature on a document that includes the organisation's UUID and the index where a member's certificate is recorded. If a third-party identity provider isn't available, a photo or video of an individual displaying a page with the organisation's title and index might suffice. Regardless of the method, the recommended approach is to provide an auditor with a verifiably random subset of members where verifiable randomness, for instance, can be generated with DRAND service to avoid data aggregation.

Coercion and bribery resistance

Illustration of time restricted receipt freeness in the Peacefounder voting system. During the election period, the system maintains both receipt-freeness and fairness. However, after the tally is published, newly submitted votes lose their fairness. The votes themselves can be published on the buletin board latter to extend the time period for receipt-freeness, reducing the effectiveness of coercers and bribers. This comes at the expense of delaying the audit process for verifying that votes have been tallied as cast.
-

Another pillar that is necessary for ensuring democratic elections is to prevent coercion and vote buying. A significant risk to the PeaceFounder system is for a briber to ask members to forward their votes through a proxy channel they control. To counter this threat, the bulletin board hides the actual votes, showing only their hashes, and gives voters an option to revote, ensuring both receipt freeness and vote fairness. A sequence number along the vote ensures that only the latest cast vote on the device matters.

This method undermines the confidence of vote buyers and coercers, as it prevents them from ensuring that the votes they've acquired will be counted in the final tally. As a consequence, they can only return bribes after votes are published on the bulletin board. (During the vote, only receipt hashes are published on the bulletin board. This serves to both commit the votes while maintaining fairness and receipt-freeness.) This arrangement erodes the credibility of bribers and coercers, making it less likely for voters to engage with them in such transactions due to the lack of a guaranteed positive/negative outcome.

A secondary concern is the potential for a coercer to ask an individual to show how they had voted on their device. To address this, only a receipt is shown. However, this receipt can be linked to the specific vote on the bulletin board. If coercion becomes a significant threat, the receipt can be visible only briefly, such as 30 minutes after casting a vote. During this window, members can manually record their details in a logbook. While this approach may reduce user-friendliness, it still serves as a robust deterrent against malware.

Malware and spyware detection

A PICTURE WITH  A RECEIPT

The last piece of the puzzle is malware and spyware resistance. An adversary could issue votes without compromising the voter's device in case of key leakage. To counter this, every vote includes a sequence number, which records evidence on the bulletin board when a vote is cast from the voter's device. Moreover, if a vote with a sequence number of one is already on the ledger, the first will override any subsequent vote with the same sequence number. This mechanism prevents malware from silently replacing inactive voter's choices.

After voting concludes and the results are published, each voter receives a bitmask of the votes included in the final tally, along with consistency proofs. Given that this approach is scalable (e.g., 1kB can handle 8192 votes, and bit compression can further reduce size), voters device's compare this bitmask with the index from their most recent vote receipt. This allows them to detect any malware activity and display an alert to the voter.

To ensure the voting process's integrity, the voter's device must remain trustworthy. With the presence of malware, there's a risk that the device could falsely reassure the voter that their vote is cast as intended. To counter this threat, after the vote is submitted, the voter receives a receipt containing a timestamp of the vote's record, the pseudonym under which it was cast, and the index where the vote resides on the ledger. Once voting concludes and all votes are disclosed on the bulletin board, the voter can cross-reference their receipt with the bulletin board, verifying that the vote at the provided index aligns with their choice and matches the timestamp when the vote was cast, as well as checking that it was included in the final tally. By maintaining a written record, voters can ensure the accuracy of their vote, safeguarding against malware alterations, unauthorised revoting, or any attempts to redirect multiple voters to a singular vote.

However, it's essential to acknowledge that voters can only detect malware interference post-vote when comparing their receipt to the bulletin board. Additionally, a voter cannot provide evidence to others that their vote was compromised by malware, which means these instances aren't audited within the PeaceFounder system. As a result, members are encouraged and are responsible for utilising more secure devices less susceptible to malware attacks. For more advanced threats, like a briber mandating malware installation for monitoring or extracting the master key, the use of tamper-resistant hardware becomes essential – an extension larger organisations or states might consider.

Implementation details and responsibilities

To illustrate the responsibilities of different entities and the structure of the communication channels, we've provided a detailed diagram. In this representation, arrows indicate which entity holds responsibility for specific resources. The primary mode of communication is facilitated through JSON within an HTTP request/reply. The JSON is also chosen as a canonical byte string format for data signing, which is selected over the ASN1 DER format due to development resource constraints.

The architecture bifurcates the bulletin board into two distinct ledgers: the braidchain and the ballot boxes. This differentiation arises from the disparate pacing and metadata requirements of records. Additionally, casting votes remains inconsequential to the braidchain's state, justifying the ledger division.

Authorised entities, namely the braidchain recorder and the ballot box collector, as specified in the guardian-issued DemeSpec record, oversee each ledger. These controllers uphold the integrity of newly added records, ensuring their coherence with the existing state. For instance, votes must adhere to a specified time window and need to be appropriately signed with member pseudonyms. Braidchain transactions demand more intricate state management, which will be described later.

In the diagram, arrows necessitating anonymous channels are designated with a TOR label originating from the member. This is a countermeasure against potential adversaries attempting to link votes to members via IP addresses. Although alternative network anonymising solutions exist, TOR is the most prominent, and together with the recent release of the Arti project for Rust, it is ideal for client-side applications [...].

Members can view the bulletin board records through the HTTP Facade, which displays them in a browser-friendly HTML. This provides a secondary channel to verify that votes are cast as intended and counted as cast. A pure JavaScript-based HTTP facade is possible, which can be hosted on a static website, simplifying deployment.

It's imperative to recognise the absence of TLS in all communications. This choice stems from the fact that data from the bulletin board is supported with a signature on Merkle tree root, rendering requests tamper-proof. Moreover, using TLS session resumption for anonymous interactions between members and the bulletin board would unintentionally make the system vulnerable to DDOS attacks during the key establishment phase. Furthermore, eliminating the need for certificate issuance and management streamlines system maintenance and deployment, enhancing usability.

Planed Core Features

The PeaceFounder system is actively focusing on integrating key features in its upcoming iterations to enhance transparency. While not exhaustive, the current list includes well-defined proposals ready for implementation.

PeaceFounderBB

https://github.com/PeaceFounder/PeaceFounder.jl/issues/22

A small democratic community often faces the challenge of limited resources, particularly when it comes to hosting bulletin board data or maintaining a comprehensive website for public record access. However, a recent trend offers a practical solution with static website hosting platforms. These platforms allow the creation of a static website directly from source code stored in a git repository without the hassle of setting up and managing certificates. A popular example is GitHub Pages, which simplifies deployment using action scripts to compile websites from sources.

Integrating a GitHub workflow to compile a webpage makes it an ideal platform for hosting a bulletin board interface. This setup has a dual advantage. The GitHub repository can serve as an authentic storage space for bulletin board records. Secondly, these records are easily accessible to the public via a web interface. Continuous integration further enhances this with build scripts, ensuring the integrity and verification of the bulletin board's contents. Those interested in verifying the bulletin board's integrity independently can either fork the repository and run the action script or clone the data locally.

Additionally, the use of the Zenodo repository enriches this system. Zenodo provides excellent archival workflows and the capability to generate a DOI link. This link serves a similar purpose to dataset references in scientific research, offering a reliable and citable record.

Cast as intended verification during the vote

https://github.com/PeaceFounder/PeaceFounder.jl/issues/21

At present, voters can only confirm that their vote has been cast as intended and accurately counted after the vote has ended and the votes are published. As the publication of votes can be delayed as a measure against coercion, it might discourage voters' participation from verifying that their vote is indeed cast as intended and counted as cast. The key issue lies in the possibility of unnoticed malware on voting devices. If voters don't verify their votes, the likelihood of malware affecting a significant number of votes without detection increases. Thus, having a procedure that enables immediate verification of the voting process is essential to engage more voters to check their votes.

The PeaceFounder system can address this by providing voters with a token displayed on the client's screen for vote verification. This token can be used in a web browser to confirm that the vote has been cast as intended. It also indicates if the vote has been superseded by a subsequent vote or one with a higher sequence number, which may occur if the member's key is compromised. To maintain receipt-freeness, the token remains valid for only a short period, such as 15 minutes. The expiration is crucial; it allows voters to verify their votes while preventing coercion or bribery attempts. It also hinders any unsolicited checks on voters' choices.

Evidence auditing with terminal API

https://github.com/PeaceFounder/PeaceFounder.jl/issues/19

The PeaceFounder system is universally verifiable, a feature ensuring that every vote is cryptographically proven to come from a registered member, even if all involved parties are corrupt. To mitigate the influence of coercion or bribery, the authority can strategically delay the publication of votes, which weakens the link between coercers and their subjects before the voters lose receipt freeness. After the votes are published, every aspect of the voting process is transparent: all proofs of votes are made publicly available. This transparency allows any interested party to audit the election results and, at their convenience, independently reproduce the announced tally.

Membership Termination

https://github.com/PeaceFounder/PeaceFounder.jl/issues/18

Under the current state of PeaceFounder, administrators face a significant limitation: they lack the capability to terminate memberships. This function is crucial in various scenarios. For instance, when a member fails to submit necessary authenticity documents within the allotted time post-registration, their membership must be annulled. Additionally, this feature is vital for addressing privacy concerns, such as when members wish to withdraw and have their associated records deleted. Furthermore, an essential aspect of membership management involves issuing new credentials in cases where a member loses their device or experiences a security breach with their key being compromised.

The process of terminating a membership in PeaceFounder presents its own set of challenges. The core difficulty lies in the inability to link a member's real identity and their current pseudonym, which prevents the removal of it in subsequent braidings. This link is only known exclusively to the member's client device, as it only knows the private key that can generate them.

A straightforward approach to address this issue involves resetting the generator in the braidchain and taking identity pseudonyms of the membership certificates as inputs to subsequent braidings. However, this method presents a significant hurdle, particularly for larger organisations. Implementing this reset each time a member is terminated can be prohibitively expensive. In particular, taking into account that the frequency of membership termination cases increases proportionally with the number of members as well as the required compute to do braidings, making this approach to scale as $O(N^2)$. Therefore, a more sophisticated and nuanced solution is needed.

Extensions

In order to avoid over-commitment, the peacefounder project currently focuses on smaller-scale organisations. This implies that a single developer must be able to maintain the system, that coercion/bribery is not of the utmost importance, and that the electoral roll is not necessary to satisfy the requirements of a law. Thus, those features are not integrated into the current design and can be considered separately as system extensions.

Proof of participation

https://github.com/PeaceFounder/PeaceFounder.jl/issues/12

Some communities may wish to nudge their members to vote, providing benefits for those who have already cast a vote or punishing those who ignore democratic decision-making. In ordinary e-voting systems, that can be easily achieved through a voter’s registry. However, this is not possible for PeaceFounder because voters are completely anonymous when they cast a vote.

One way to address this issue is with a blind signature scheme. The voter takes his identity pseudonym, blinds it with a random factor and includes that in the vote when sent to the ballot box. The collector checks that the vote is valid and, if so, signs the blinded group element at the time when the vote is recorded in the ledger. The blind signature is reused if the voter has already cast a ballot.

The voter then receives an acknowledgement that the vote is permanently recorded in the chain together with the blind signature and timestamp. The voter unblinds the blind signature with its blinding factor and obtains a signature on his identity pseudonym as proof of participation. That can then be safely shown publicly for anyone who wants to see that the person has voted without being linked to the cast vote.

Selection's asymmetric encryption

https://github.com/PeaceFounder/PeaceFounder.jl/issues/16

To maintain the impartiality of auditors/monitors with regard to votes they oversee and further deter potential bribery attempts, an asymmetric encryption method for vote selection is advisable. Under this protocol, the voter's device encrypts a symmetric key asymmetrically and then proceeds to encrypt the vote selection using this symmetric key. The key and the encrypted selection are included in the vote, which is then signed using a pseudonym. Upon receiving the vote, after authenticating its signature, the system decrypts the symmetric key, followed by the vote selection. To ensure the decryption's integrity, a zero-knowledge proof is provided and subsequently published alongside the vote on the bulletin board.

Coerced vote tagging

https://github.com/PeaceFounder/PeaceFounder.jl/issues/16

A threat where coercers forcibly dictate voters' choices while confiscating their devices is a pressing concern beyond the PeaceFounder system. A common solution to such a problem is equipping voters with an option to create a secondary PIN code, which works exactly as the primary PIN code except that the votes are tagged as coerced.

To safeguard against coercers potentially discerning this distinction using a proxy vote submission method, the coercion tag can be asymmetrically encrypted as a group element before transmitting it to the ballot box collector. Upon receipt, the collector would record and then decrypt the coercion tag. A zero-knowledge proof of decryption would ensure the collector's integrity, published together with a vote on the bulletin board.

Votes are disclosed at the conclusion of the process, indicating any tags applied. By lengthening the gap between the tally announcement and the release of the votes, we can diminish the impact of coercive threats and deter unscrupulous voters from awaiting compensation, hinging on the assumption of the briber's credibility. Technically, this mechanism ensures receipt freeness until they appear on the ballot box ledger.

This strategy presumes that no adversarial entity has infiltrated the collector system. To mitigate such risks, deploying multiple collectors, to which voters are randomly pre-assigned, is advised. This introduces a level of inter-collector accountability, as aggregated results should align. Notably, while receipt freeness is limited, the method retains full transparency: all parties can validate the tally's accuracy and verify every vote's eligibility and unlinkability, as well as the validity of the coercion tag.

Sempled Electoral Roll Audits

https://github.com/PeaceFounder/PeaceFounder.jl/issues/17

In order to ensure the integrity of elections, it is crucial that independent auditors audit the legitimacy of members. However, the records that support the membership cannot be made public as it would violate the members' right to freedom of association and would also infringe on GDPR. Keeping these records confidential while ensuring they are sufficiently audited can be challenging and may require reducing openness to prevent any possible leaks.

To overcome this dilemma in favour of more openness, a sampling of the electoral roll could be used. A large enough sample size can provide sufficient confidence that a potentially corrupt registrar could not have affected the election result, whereas keeping it small reduces the impact of leaks from the auditors. This lowers the trust barrier and opens the electoral roll auditing for more independent parties.

Early leaked private key detection

In a situation where the adversary has acquired a member's private key, they can form valid votes that can be included in the bulletin board. To detect that a bitmask is included in the ballot box commit, which the voter retrieves together with consistency proofs. That allows us to see whether tallied votes have been cast from the member's device as it can look into the bitmask for tallied votes after the vote. However, when a member votes after the adversary, the bulletin board could inform about the fact in the receipt.

The problem is that showing on receipt whether the vote is a final submission considered for inclusion in the tally can impede the voter's ability to revote if the coercer/briber waits until the last minute before submitting their acquired vote. This circumvents a measure where publishing votes is delayed for an extended time after the tally is published for eroding trust in bribers and delaying punishment from coercers. Therefore, the response status needs to be asymmetrically encrypted.

The status code can be encrypted as a group element and decrypted on the voter's device. If the submitted vote is not final, the collector encrypts a group element representing status addressed to the pseudonym that cast the vote. The device receives the receipt, and as it only has the private key, the status code can be shown. That allows members to see early whether the vote was already cast with the provided sequence number and superseded it with possible recasting.

Sharded Ballots

In democratic processes, it's conceivable that voters may be presented with an extensive list of ballot questions to express their opinions. However, as evident with comprehensive surveys, there is a noticeable decline in response rates as the number of questions escalates. Further complicating matters is the phenomenon known as the 'voter's paradox,' wherein the impact of a singular vote diminishes in larger elections. Both challenges can be addressed by sharding lengthy ballots among the entire voter base.

In the PeaceFounder system, sharding is trivial due to votes being cast pseudonymously. The initial step in the sharding involves determining all feasible divisions of the ballot and methodically enumerating them. Subsequently, these shards are allocated to pseudonyms, achieved by systematically sorting and matching them in sequence.

Nevertheless, a pronounced security concern emerges. Suppose an adversary assumes control over the proposer and possesses knowledge of a select group of pseudonym owners and their inclinations. In that case, they can manipulate the election outcome by tailoring the proposal and shards. Specifically, critical questions can be allocated to a limited cohort, skewing results in their favour.

To counteract this vulnerability, it's imperative for the proposer to commit to both the ballot and its associated shards, followed by a lottery to randomise the pseudonym list. Leveraging a DRAND service, which collaborates with multiple entities to execute threshold decryption, ensures the generation of predetermined, incorruptible random numbers [...]. These numbers subsequently serve as salt for hashing pseudonyms, which are sorted and allocated to shards accordingly. A critical aspect of this method is making sure the proposal is committed before the lottery result is announced to prevent adversaries from taking advantage of waiting for a favourable lottery outcome. This necessitates the involvement of auditors/monitors to timestamp the braidchain ledger commitments externally.

+

Another pillar that is necessary for ensuring democratic elections is to prevent coercion and vote buying. A significant risk to the PeaceFounder system is for a briber to ask members to forward their votes through a proxy channel they control. To counter this threat, the bulletin board hides the actual votes, showing only their hashes, and gives voters an option to revote, ensuring both receipt freeness and vote fairness. A sequence number along the vote ensures that only the latest cast vote on the device matters.

This method undermines the confidence of vote buyers and coercers, as it prevents them from ensuring that the votes they've acquired will be counted in the final tally. As a consequence, they can only return bribes after votes are published on the bulletin board. (During the vote, only receipt hashes are published on the bulletin board. This serves to both commit the votes while maintaining fairness and receipt-freeness.) This arrangement erodes the credibility of bribers and coercers, making it less likely for voters to engage with them in such transactions due to the lack of a guaranteed positive/negative outcome.

A secondary concern is the potential for a coercer to ask an individual to show how they had voted on their device. To address this, only a receipt is shown. However, this receipt can be linked to the specific vote on the bulletin board. If coercion becomes a significant threat, the receipt can be visible only briefly, such as 30 minutes after casting a vote. During this window, members can manually record their details in a logbook. While this approach may reduce user-friendliness, it still serves as a robust deterrent against malware.

Malware and spyware detection

A PICTURE WITH  A RECEIPT

The last piece of the puzzle is malware and spyware resistance. An adversary could issue votes without compromising the voter's device in case of key leakage. To counter this, every vote includes a sequence number, which records evidence on the bulletin board when a vote is cast from the voter's device. Moreover, if a vote with a sequence number of one is already on the ledger, the first will override any subsequent vote with the same sequence number. This mechanism prevents malware from silently replacing inactive voter's choices.

After voting concludes and the results are published, each voter receives a bitmask of the votes included in the final tally, along with consistency proofs. Given that this approach is scalable (e.g., 1kB can handle 8192 votes, and bit compression can further reduce size), voters device's compare this bitmask with the index from their most recent vote receipt. This allows them to detect any malware activity and display an alert to the voter.

To ensure the voting process's integrity, the voter's device must remain trustworthy. With the presence of malware, there's a risk that the device could falsely reassure the voter that their vote is cast as intended. To counter this threat, after the vote is submitted, the voter receives a receipt containing a timestamp of the vote's record, the pseudonym under which it was cast, and the index where the vote resides on the ledger. Once voting concludes and all votes are disclosed on the bulletin board, the voter can cross-reference their receipt with the bulletin board, verifying that the vote at the provided index aligns with their choice and matches the timestamp when the vote was cast, as well as checking that it was included in the final tally. By maintaining a written record, voters can ensure the accuracy of their vote, safeguarding against malware alterations, unauthorised revoting, or any attempts to redirect multiple voters to a singular vote.

However, it's essential to acknowledge that voters can only detect malware interference post-vote when comparing their receipt to the bulletin board. Additionally, a voter cannot provide evidence to others that their vote was compromised by malware, which means these instances aren't audited within the PeaceFounder system. As a result, members are encouraged and are responsible for utilising more secure devices less susceptible to malware attacks. For more advanced threats, like a briber mandating malware installation for monitoring or extracting the master key, the use of tamper-resistant hardware becomes essential – an extension larger organisations or states might consider.

Implementation details and responsibilities

To illustrate the responsibilities of different entities and the structure of the communication channels, we've provided a detailed diagram. In this representation, arrows indicate which entity holds responsibility for specific resources. The primary mode of communication is facilitated through JSON within an HTTP request/reply. The JSON is also chosen as a canonical byte string format for data signing, which is selected over the ASN1 DER format due to development resource constraints.

The architecture bifurcates the bulletin board into two distinct ledgers: the braidchain and the ballot boxes. This differentiation arises from the disparate pacing and metadata requirements of records. Additionally, casting votes remains inconsequential to the braidchain's state, justifying the ledger division.

Authorised entities, namely the braidchain recorder and the ballot box collector, as specified in the guardian-issued DemeSpec record, oversee each ledger. These controllers uphold the integrity of newly added records, ensuring their coherence with the existing state. For instance, votes must adhere to a specified time window and need to be appropriately signed with member pseudonyms. Braidchain transactions demand more intricate state management, which will be described later.

In the diagram, arrows necessitating anonymous channels are designated with a TOR label originating from the member. This is a countermeasure against potential adversaries attempting to link votes to members via IP addresses. Although alternative network anonymising solutions exist, TOR is the most prominent, and together with the recent release of the Arti project for Rust, it is ideal for client-side applications [...].

Members can view the bulletin board records through the HTTP Facade, which displays them in a browser-friendly HTML. This provides a secondary channel to verify that votes are cast as intended and counted as cast. A pure JavaScript-based HTTP facade is possible, which can be hosted on a static website, simplifying deployment.

It's imperative to recognise the absence of TLS in all communications. This choice stems from the fact that data from the bulletin board is supported with a signature on Merkle tree root, rendering requests tamper-proof. Moreover, using TLS session resumption for anonymous interactions between members and the bulletin board would unintentionally make the system vulnerable to DDOS attacks during the key establishment phase. Furthermore, eliminating the need for certificate issuance and management streamlines system maintenance and deployment, enhancing usability.

Planed Core Features

The PeaceFounder system is actively focusing on integrating key features in its upcoming iterations to enhance transparency. While not exhaustive, the current list includes well-defined proposals ready for implementation.

PeaceFounderBB

https://github.com/PeaceFounder/PeaceFounder.jl/issues/22

A small democratic community often faces the challenge of limited resources, particularly when it comes to hosting bulletin board data or maintaining a comprehensive website for public record access. However, a recent trend offers a practical solution with static website hosting platforms. These platforms allow the creation of a static website directly from source code stored in a git repository without the hassle of setting up and managing certificates. A popular example is GitHub Pages, which simplifies deployment using action scripts to compile websites from sources.

Integrating a GitHub workflow to compile a webpage makes it an ideal platform for hosting a bulletin board interface. This setup has a dual advantage. The GitHub repository can serve as an authentic storage space for bulletin board records. Secondly, these records are easily accessible to the public via a web interface. Continuous integration further enhances this with build scripts, ensuring the integrity and verification of the bulletin board's contents. Those interested in verifying the bulletin board's integrity independently can either fork the repository and run the action script or clone the data locally.

Additionally, the use of the Zenodo repository enriches this system. Zenodo provides excellent archival workflows and the capability to generate a DOI link. This link serves a similar purpose to dataset references in scientific research, offering a reliable and citable record.

Cast as intended verification during the vote

https://github.com/PeaceFounder/PeaceFounder.jl/issues/21

At present, voters can only confirm that their vote has been cast as intended and accurately counted after the vote has ended and the votes are published. As the publication of votes can be delayed as a measure against coercion, it might discourage voters' participation from verifying that their vote is indeed cast as intended and counted as cast. The key issue lies in the possibility of unnoticed malware on voting devices. If voters don't verify their votes, the likelihood of malware affecting a significant number of votes without detection increases. Thus, having a procedure that enables immediate verification of the voting process is essential to engage more voters to check their votes.

The PeaceFounder system can address this by providing voters with a token displayed on the client's screen for vote verification. This token can be used in a web browser to confirm that the vote has been cast as intended. It also indicates if the vote has been superseded by a subsequent vote or one with a higher sequence number, which may occur if the member's key is compromised. To maintain receipt-freeness, the token remains valid for only a short period, such as 15 minutes. The expiration is crucial; it allows voters to verify their votes while preventing coercion or bribery attempts. It also hinders any unsolicited checks on voters' choices.

Evidence auditing with terminal API

https://github.com/PeaceFounder/PeaceFounder.jl/issues/19

The PeaceFounder system is universally verifiable, a feature ensuring that every vote is cryptographically proven to come from a registered member, even if all involved parties are corrupt. To mitigate the influence of coercion or bribery, the authority can strategically delay the publication of votes, which weakens the link between coercers and their subjects before the voters lose receipt freeness. After the votes are published, every aspect of the voting process is transparent: all proofs of votes are made publicly available. This transparency allows any interested party to audit the election results and, at their convenience, independently reproduce the announced tally.

Membership Termination

https://github.com/PeaceFounder/PeaceFounder.jl/issues/18

Under the current state of PeaceFounder, administrators face a significant limitation: they lack the capability to terminate memberships. This function is crucial in various scenarios. For instance, when a member fails to submit necessary authenticity documents within the allotted time post-registration, their membership must be annulled. Additionally, this feature is vital for addressing privacy concerns, such as when members wish to withdraw and have their associated records deleted. Furthermore, an essential aspect of membership management involves issuing new credentials in cases where a member loses their device or experiences a security breach with their key being compromised.

The process of terminating a membership in PeaceFounder presents its own set of challenges. The core difficulty lies in the inability to link a member's real identity and their current pseudonym, which prevents the removal of it in subsequent braidings. This link is only known exclusively to the member's client device, as it only knows the private key that can generate them.

A straightforward approach to address this issue involves resetting the generator in the braidchain and taking identity pseudonyms of the membership certificates as inputs to subsequent braidings. However, this method presents a significant hurdle, particularly for larger organisations. Implementing this reset each time a member is terminated can be prohibitively expensive. In particular, taking into account that the frequency of membership termination cases increases proportionally with the number of members as well as the required compute to do braidings, making this approach to scale as $O(N^2)$. Therefore, a more sophisticated and nuanced solution is needed.

Extensions

In order to avoid over-commitment, the peacefounder project currently focuses on smaller-scale organisations. This implies that a single developer must be able to maintain the system, that coercion/bribery is not of the utmost importance, and that the electoral roll is not necessary to satisfy the requirements of a law. Thus, those features are not integrated into the current design and can be considered separately as system extensions.

Proof of participation

https://github.com/PeaceFounder/PeaceFounder.jl/issues/12

Some communities may wish to nudge their members to vote, providing benefits for those who have already cast a vote or punishing those who ignore democratic decision-making. In ordinary e-voting systems, that can be easily achieved through a voter’s registry. However, this is not possible for PeaceFounder because voters are completely anonymous when they cast a vote.

One way to address this issue is with a blind signature scheme. The voter takes his identity pseudonym, blinds it with a random factor and includes that in the vote when sent to the ballot box. The collector checks that the vote is valid and, if so, signs the blinded group element at the time when the vote is recorded in the ledger. The blind signature is reused if the voter has already cast a ballot.

The voter then receives an acknowledgement that the vote is permanently recorded in the chain together with the blind signature and timestamp. The voter unblinds the blind signature with its blinding factor and obtains a signature on his identity pseudonym as proof of participation. That can then be safely shown publicly for anyone who wants to see that the person has voted without being linked to the cast vote.

Selection's asymmetric encryption

https://github.com/PeaceFounder/PeaceFounder.jl/issues/16

To maintain the impartiality of auditors/monitors with regard to votes they oversee and further deter potential bribery attempts, an asymmetric encryption method for vote selection is advisable. Under this protocol, the voter's device encrypts a symmetric key asymmetrically and then proceeds to encrypt the vote selection using this symmetric key. The key and the encrypted selection are included in the vote, which is then signed using a pseudonym. Upon receiving the vote, after authenticating its signature, the system decrypts the symmetric key, followed by the vote selection. To ensure the decryption's integrity, a zero-knowledge proof is provided and subsequently published alongside the vote on the bulletin board.

Coerced vote tagging

https://github.com/PeaceFounder/PeaceFounder.jl/issues/16

A threat where coercers forcibly dictate voters' choices while confiscating their devices is a pressing concern beyond the PeaceFounder system. A common solution to such a problem is equipping voters with an option to create a secondary PIN code, which works exactly as the primary PIN code except that the votes are tagged as coerced.

To safeguard against coercers potentially discerning this distinction using a proxy vote submission method, the coercion tag can be asymmetrically encrypted as a group element before transmitting it to the ballot box collector. Upon receipt, the collector would record and then decrypt the coercion tag. A zero-knowledge proof of decryption would ensure the collector's integrity, published together with a vote on the bulletin board.

Votes are disclosed at the conclusion of the process, indicating any tags applied. By lengthening the gap between the tally announcement and the release of the votes, we can diminish the impact of coercive threats and deter unscrupulous voters from awaiting compensation, hinging on the assumption of the briber's credibility. Technically, this mechanism ensures receipt freeness until they appear on the ballot box ledger.

This strategy presumes that no adversarial entity has infiltrated the collector system. To mitigate such risks, deploying multiple collectors, to which voters are randomly pre-assigned, is advised. This introduces a level of inter-collector accountability, as aggregated results should align. Notably, while receipt freeness is limited, the method retains full transparency: all parties can validate the tally's accuracy and verify every vote's eligibility and unlinkability, as well as the validity of the coercion tag.

Sempled Electoral Roll Audits

https://github.com/PeaceFounder/PeaceFounder.jl/issues/17

In order to ensure the integrity of elections, it is crucial that independent auditors audit the legitimacy of members. However, the records that support the membership cannot be made public as it would violate the members' right to freedom of association and would also infringe on GDPR. Keeping these records confidential while ensuring they are sufficiently audited can be challenging and may require reducing openness to prevent any possible leaks.

To overcome this dilemma in favour of more openness, a sampling of the electoral roll could be used. A large enough sample size can provide sufficient confidence that a potentially corrupt registrar could not have affected the election result, whereas keeping it small reduces the impact of leaks from the auditors. This lowers the trust barrier and opens the electoral roll auditing for more independent parties.

Early leaked private key detection

In a situation where the adversary has acquired a member's private key, they can form valid votes that can be included in the bulletin board. To detect that a bitmask is included in the ballot box commit, which the voter retrieves together with consistency proofs. That allows us to see whether tallied votes have been cast from the member's device as it can look into the bitmask for tallied votes after the vote. However, when a member votes after the adversary, the bulletin board could inform about the fact in the receipt.

The problem is that showing on receipt whether the vote is a final submission considered for inclusion in the tally can impede the voter's ability to revote if the coercer/briber waits until the last minute before submitting their acquired vote. This circumvents a measure where publishing votes is delayed for an extended time after the tally is published for eroding trust in bribers and delaying punishment from coercers. Therefore, the response status needs to be asymmetrically encrypted.

The status code can be encrypted as a group element and decrypted on the voter's device. If the submitted vote is not final, the collector encrypts a group element representing status addressed to the pseudonym that cast the vote. The device receives the receipt, and as it only has the private key, the status code can be shown. That allows members to see early whether the vote was already cast with the provided sequence number and superseded it with possible recasting.

Sharded Ballots

In democratic processes, it's conceivable that voters may be presented with an extensive list of ballot questions to express their opinions. However, as evident with comprehensive surveys, there is a noticeable decline in response rates as the number of questions escalates. Further complicating matters is the phenomenon known as the 'voter's paradox,' wherein the impact of a singular vote diminishes in larger elections. Both challenges can be addressed by sharding lengthy ballots among the entire voter base.

In the PeaceFounder system, sharding is trivial due to votes being cast pseudonymously. The initial step in the sharding involves determining all feasible divisions of the ballot and methodically enumerating them. Subsequently, these shards are allocated to pseudonyms, achieved by systematically sorting and matching them in sequence.

Nevertheless, a pronounced security concern emerges. Suppose an adversary assumes control over the proposer and possesses knowledge of a select group of pseudonym owners and their inclinations. In that case, they can manipulate the election outcome by tailoring the proposal and shards. Specifically, critical questions can be allocated to a limited cohort, skewing results in their favour.

To counteract this vulnerability, it's imperative for the proposer to commit to both the ballot and its associated shards, followed by a lottery to randomise the pseudonym list. Leveraging a DRAND service, which collaborates with multiple entities to execute threshold decryption, ensures the generation of predetermined, incorruptible random numbers [...]. These numbers subsequently serve as salt for hashing pseudonyms, which are sorted and allocated to shards accordingly. A critical aspect of this method is making sure the proposal is committed before the lottery result is announced to prevent adversaries from taking advantage of waiting for a favourable lottery outcome. This necessitates the involvement of auditors/monitors to timestamp the braidchain ledger commitments externally.

diff --git a/dev/schedulers/index.html b/dev/schedulers/index.html index acecffe..9544c56 100644 --- a/dev/schedulers/index.html +++ b/dev/schedulers/index.html @@ -20,6 +20,6 @@ catch retry!(scheduler) end -end

In the event loop one manages a state machine which can succed and fail. If it succeds a scheduled time is taken out from the scheduler and proceeds waiting the next event. In the case event at scheduled time had failed the scheduler is notified with retry! method and attempts to run the event loop againafter retry_interval until succeeds.

source
Base.lockMethod
lock(scheduler::Scheduler)

Lock a scheduler. This is necessary to avoid simultanous modifications of the schedule field. Note that other Scheduler fields are not protected with the lock as thoose are considered internal.

source
Base.notifyMethod
notify(scheduler::Scheduler[, value])

Notify a scheduler with a value which is returned at wait.

source
Base.waitMethod
wait(scheduler::Scheduler)

Wait until next event is reached and return it's value. In the case event have run through smoothelly the scheduler event is droped with the next wait call. See also retry! method.

source
PeaceFounder.Schedulers.next_eventMethod
next_event(scheduler::Scheduler)

Return the next event in seconds and coresponding event value. Return nothing if no events are scheduled.

source
PeaceFounder.Schedulers.retry!Method
retry!(scheduler::Scheduler)

Notifies the scheduler that event have run unsucesfully which reschedules it after specified retry_time(See Scheduler).

source
PeaceFounder.Schedulers.schedule!Method
schedule!(scheduler::Scheduler, timestamp::DateTime[, value])

Schedule an event at timestamp with a provided value. To avoid messing up a schedule acquire a scheduler's lock before adding the event as:

lock(scheduler) do
+end

In the event loop one manages a state machine which can succed and fail. If it succeds a scheduled time is taken out from the scheduler and proceeds waiting the next event. In the case event at scheduled time had failed the scheduler is notified with retry! method and attempts to run the event loop againafter retry_interval until succeeds.

source
Base.lockMethod
lock(scheduler::Scheduler)

Lock a scheduler. This is necessary to avoid simultanous modifications of the schedule field. Note that other Scheduler fields are not protected with the lock as thoose are considered internal.

source
Base.notifyMethod
notify(scheduler::Scheduler[, value])

Notify a scheduler with a value which is returned at wait.

source
Base.waitMethod
wait(scheduler::Scheduler)

Wait until next event is reached and return it's value. In the case event have run through smoothelly the scheduler event is droped with the next wait call. See also retry! method.

source
PeaceFounder.Schedulers.next_eventMethod
next_event(scheduler::Scheduler)

Return the next event in seconds and coresponding event value. Return nothing if no events are scheduled.

source
PeaceFounder.Schedulers.retry!Method
retry!(scheduler::Scheduler)

Notifies the scheduler that event have run unsucesfully which reschedules it after specified retry_time(See Scheduler).

source
PeaceFounder.Schedulers.schedule!Method
schedule!(scheduler::Scheduler, timestamp::DateTime[, value])

Schedule an event at timestamp with a provided value. To avoid messing up a schedule acquire a scheduler's lock before adding the event as:

lock(scheduler) do
     schedule!(scheduler, now() + Second(1), value)
-end
source
PeaceFounder.Schedulers.waituntilMethod
waituntil(time::DateTime)

Waits until given time is reached.

source
+endsource
PeaceFounder.Schedulers.waituntilMethod
waituntil(time::DateTime)

Waits until given time is reached.

source
diff --git a/dev/schema/index.html b/dev/schema/index.html index c6321e0..b33cf92 100644 --- a/dev/schema/index.html +++ b/dev/schema/index.html @@ -29,4 +29,4 @@ dom_id: '#swagger-ui', }); }; - + diff --git a/dev/search_index.js b/dev/search_index.js index 031920f..1744954 100644 --- a/dev/search_index.js +++ b/dev/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"audittools/#PeaceFounder.AuditTools","page":"PeaceFounder.Core.AuditTools","title":"PeaceFounder.AuditTools","text":"","category":"section"},{"location":"audittools/","page":"PeaceFounder.Core.AuditTools","title":"PeaceFounder.Core.AuditTools","text":"Note: follow the feature proposal https://github.com/PeaceFounder/PeaceFounder.jl/issues/19","category":"page"},{"location":"audittools/","page":"PeaceFounder.Core.AuditTools","title":"PeaceFounder.Core.AuditTools","text":"PeaceFounder.Core.AuditTools","category":"page"},{"location":"audittools/","page":"PeaceFounder.Core.AuditTools","title":"PeaceFounder.Core.AuditTools","text":"Modules = [PeaceFounder.Core.AuditTools]\nOrder = [:module, :type, :function]","category":"page"},{"location":"audittools/#PeaceFounder.Core.AuditTools","page":"PeaceFounder.Core.AuditTools","title":"PeaceFounder.Core.AuditTools","text":"After ellections have ended the collector publishes a tally. To assert that votes have been accuratelly counted and that only legitimate voters have participated an audit takes place.\n\nEvery voter after ellections receives a final tally together with a consistency proof which proves that their vote is included in the ledger which have produced the tally. From the voter client voter reads four important parameters for the ballotbox:\n\ndeme_uuid: an UUID of the deme where the proposal is registered;\nproposal_index: a index at which the proposal is recorded in the braidchain ledger;\nledger_length: a number of collected votes in the ledger;\nledger_root: a ballotbox ledger root checksum.\n\nThe auditor also knows a hasher deme uses to make checksums which is immutable at the moment deme is created.\n\nLet's consider abstract functions to retrieve ballotbox and braidchain ledger archives from the internet with get_ballotbox_archive and get_braidchain_archive then the auditing can be done with a following script:\n\nbraidchain_archive = get_ballotbox_archive(uuid)\nballotbox_archive = get_ballotbox_archive(uuid, proposal_index)[1:ledger_length]\n\n@test checksum(ballotbox_archive, hasher) == ledger_root\n@test isbinding(braidchain_archive, ballotbox_archive, hasher)\n\nspec = crypto(braidchain_archive)\n\n@test audit(ballotbox_archive, spec)\n@test audit(braidchain_archive)\n\n@show tally(ballotbox_archive)\n\nNote that spec is read from the DemeSpec record in the braidchain which can be trusted as the tree braidchain ledger checksum is listed within a proposal's anchor. The proposal is the first record in history tree for the ballotbox thus it is bound to ledger_root checksum and so demespec record is also tied to ledger_root.\n\nFor convinience an audit method is provided which audits both archives at the same time:\n\nbraidchain_archive = get_ballotbox_archive(uuid)\nballotbox_archive = get_ballotbox_archive(uuid, proposal_index)[1:ledger_length]\n\n@test checksum(ballotbox_archive, hasher) == ledger_root\n@test audit(braidchain_archive, ballotbox_archive, hasher)\n\n@show tally(ballotbox_archive)\n\nNote that this audit does not check honesty of the registrar that it have not admitted fake users to gain more influence in the ellection result. Properties being verified by the audit:\n\nLegitimacy: only and all eligiable voters cast their votes;\nFairness: every eligiable voter can vote at most once;\nImmutability: no vote can be deleted or modified when recorded in the ledger; \nTallied as Cast: all cast votes are counted honestly to predetermined procedure; \nSoftware independence: the previously audited properties for the evidence does not \n\ndepend on a trust in honest execution of peacefounder service nor honesty of the braiders who provides new pseudonyms for the deme members. In other words the previously listed properties would not be altered if adversary would have a full control over the peacefounder service and the braiders. \n\nThe immutability is ensured from voter's clients updating their consistency proof chain which includes their vote. If the vote gets removed from a chain every single voter who had cast their vote would get a proof for inconsistent ledger state called blame. The blame can be made public by the voter without revealing it's vote and thus ensures immutability and also persitance after votes are published. The auditable part here are the votes themselves signed with pseudonym which contract voter's clients to follow up at latter periods with consistency proofs. On top of that, other monitors can synchronize the ballotbox ledger and add assurances that way.\n\n\n\n\n\n","category":"module"},{"location":"audittools/#PeaceFounder.Core.AuditTools.BallotBoxArchive","page":"PeaceFounder.Core.AuditTools","title":"PeaceFounder.Core.AuditTools.BallotBoxArchive","text":"struct BallotBoxArchive\n proposal::Proposal\n seed::Digest\n ledger::Vector{CastRecord}\nend\n\nRepresents a ballotbox ledger archive. Contains a proposal for which votes have been collected; seed initialized by collector and ledger containing all cast records.\n\n\n\n\n\n","category":"type"},{"location":"audittools/#PeaceFounder.Core.AuditTools.BraidChainArchive","page":"PeaceFounder.Core.AuditTools","title":"PeaceFounder.Core.AuditTools.BraidChainArchive","text":"struct BraidChainArchive\n ledger::Vector{Transaction}\nend\n\nRepresents a braidchain ledger archive. \n\n\n\n\n\n","category":"type"},{"location":"audittools/#PeaceFounder.Core.AuditTools.archive","page":"PeaceFounder.Core.AuditTools","title":"PeaceFounder.Core.AuditTools.archive","text":"archive(ledger::BraidChainController)::BraidChainArchive\narchive(ledger::BallotBox)::BallotBoxArchive\n\nForm an archive of braidchain or ballotbox which can be sent over wire to be audited. \n\n\n\n\n\n","category":"function"},{"location":"audittools/#PeaceFounder.Core.AuditTools.audit","page":"PeaceFounder.Core.AuditTools","title":"PeaceFounder.Core.AuditTools.audit","text":"audit(archive::BallotBoxArchive, spec::CryptoSpec)\n\nCheck that recorded votes are consistent with proposal ballot and that cryptographic signature of every recorded vote is correct. –-\n\naudit(archive::BraidChainArchive)\n\nCheck that the braidchain ledger is consistent. Runs through \n\n- [`audit_members`](@ref)\n- [`audit_braids`](@ref) \n- [`audit_proposals`](@ref)\n- [`audit_roster`](@ref)\n- [`audit_lots`](@ref)\n\n\n\naudit(ballotbox_archive::BraidChainArchive, ballotbox_archive::BallotBoxArchive, hasher)\n\nAudits each ledger seperatelly and then checks consistency between themselves: such as that only valid member pseudonyms have cast their votes, that proposal is available in the braidchain ledger.\n\n\n\n\n\n","category":"function"},{"location":"audittools/#PeaceFounder.Core.AuditTools.audit_braids","page":"PeaceFounder.Core.AuditTools","title":"PeaceFounder.Core.AuditTools.audit_braids","text":"audit_braids(ledger::BraidChainArchive)\n\nIndividually check every braid and it's zero knowledge proof and it's consistency with the chain. For the latter, that input pseudonyms and relative generator to a braid come from a previous output braiding output and newly registered members. \n\n\n\n\n\n","category":"function"},{"location":"audittools/#PeaceFounder.Core.AuditTools.audit_members","page":"PeaceFounder.Core.AuditTools","title":"PeaceFounder.Core.AuditTools.audit_members","text":"audit_members(ledger::BraidChainArchive)\n\nCheck every member registration certificate consistency with the ledger. In particular: - Admission approved by a trusted entity at that time; - Membership approved by a admitted identity only once; - Every member psuedonym is generated with the current relative generator in the braidchain ledger;\n\n\n\n\n\n","category":"function"},{"location":"audittools/#PeaceFounder.Core.AuditTools.audit_proposals","page":"PeaceFounder.Core.AuditTools","title":"PeaceFounder.Core.AuditTools.audit_proposals","text":"audit_proposals(ledger::BraidChainArchive)\n\nCheck every proposal for it's consistency with the chain. In particular: - Every proposal is signed by a valid proposer at the time of inclusion in the ledger; - Anchor in within the proposal is consistent with the ledger; - Every proposal has a unique UUID as well as it's title is sufficiently different from previous ones;\n\n\n\n\n\n","category":"function"},{"location":"audittools/#PeaceFounder.Core.AuditTools.audit_roster","page":"PeaceFounder.Core.AuditTools","title":"PeaceFounder.Core.AuditTools.audit_roster","text":"audit_roster(ledger::BraidChainArchive)\n\nCheck that every DemeSpec transaction in the ledger is correctly signed by the guardian. \n\n\n\n\n\n","category":"function"},{"location":"audittools/#PeaceFounder.Core.AuditTools.checksum","page":"PeaceFounder.Core.AuditTools","title":"PeaceFounder.Core.AuditTools.checksum","text":"checksum(ledger::Union{BraidChainArchive, BallotBoxArchive}, hasher)::Digest\n\nCalculate a history tree root from a given ledger records. Meant to be used to check integrity of the received data. \n\n\n\n\n\n","category":"function"},{"location":"schedulers/#PeaceFounder.Schedulers","page":"PeaceFounder.Schedulers","title":"PeaceFounder.Schedulers","text":"","category":"section"},{"location":"schedulers/","page":"PeaceFounder.Schedulers","title":"PeaceFounder.Schedulers","text":"Modules = [PeaceFounder.Schedulers]\nOrder = [:type, :function]","category":"page"},{"location":"schedulers/#PeaceFounder.Schedulers.Scheduler","page":"PeaceFounder.Schedulers","title":"PeaceFounder.Schedulers.Scheduler","text":"mutable struct Scheduler\n condition::Condition\n pool_interval::Union{Int, Nothing}\n retry_interval::Union{Int, Nothing}\n delay::Int\n started::Bool\n finished::Bool\n schedule::Vector{Tuple{DateTime, <:Any}}\nend\n\nRepresents a waitable object which resumes at predetermined scheduled times. A typical use for it is in the event loop like:\n\nscheduler = Scheduler(; retry_interval = 1)\n\nlock(scheduler) do \n schedule!(scheduler, now() + Second(1), value)\nend\n\nwhile true\n value = wait(scheduler)\n try\n # Do some stuff\n catch\n retry!(scheduler)\n end\nend\n\nIn the event loop one manages a state machine which can succed and fail. If it succeds a scheduled time is taken out from the scheduler and proceeds waiting the next event. In the case event at scheduled time had failed the scheduler is notified with retry! method and attempts to run the event loop againafter retry_interval until succeeds. \n\n\n\n\n\n","category":"type"},{"location":"schedulers/#Base.lock-Tuple{PeaceFounder.Schedulers.Scheduler}","page":"PeaceFounder.Schedulers","title":"Base.lock","text":"lock(scheduler::Scheduler)\n\nLock a scheduler. This is necessary to avoid simultanous modifications of the schedule field. Note that other Scheduler fields are not protected with the lock as thoose are considered internal. \n\n\n\n\n\n","category":"method"},{"location":"schedulers/#Base.notify-Tuple{PeaceFounder.Schedulers.Scheduler}","page":"PeaceFounder.Schedulers","title":"Base.notify","text":"notify(scheduler::Scheduler[, value])\n\nNotify a scheduler with a value which is returned at wait.\n\n\n\n\n\n","category":"method"},{"location":"schedulers/#Base.wait-Tuple{PeaceFounder.Schedulers.Scheduler}","page":"PeaceFounder.Schedulers","title":"Base.wait","text":"wait(scheduler::Scheduler)\n\nWait until next event is reached and return it's value. In the case event have run through smoothelly the scheduler event is droped with the next wait call. See also retry! method.\n\n\n\n\n\n","category":"method"},{"location":"schedulers/#PeaceFounder.Schedulers.next_event-Tuple{PeaceFounder.Schedulers.Scheduler}","page":"PeaceFounder.Schedulers","title":"PeaceFounder.Schedulers.next_event","text":"next_event(scheduler::Scheduler)\n\nReturn the next event in seconds and coresponding event value. Return nothing if no events are scheduled.\n\n\n\n\n\n","category":"method"},{"location":"schedulers/#PeaceFounder.Schedulers.retry!-Tuple{PeaceFounder.Schedulers.Scheduler}","page":"PeaceFounder.Schedulers","title":"PeaceFounder.Schedulers.retry!","text":"retry!(scheduler::Scheduler)\n\nNotifies the scheduler that event have run unsucesfully which reschedules it after specified retry_time(See Scheduler). \n\n\n\n\n\n","category":"method"},{"location":"schedulers/#PeaceFounder.Schedulers.schedule!-Tuple{PeaceFounder.Schedulers.Scheduler, Dates.DateTime, Any}","page":"PeaceFounder.Schedulers","title":"PeaceFounder.Schedulers.schedule!","text":"schedule!(scheduler::Scheduler, timestamp::DateTime[, value])\n\nSchedule an event at timestamp with a provided value. To avoid messing up a schedule acquire a scheduler's lock before adding the event as:\n\nlock(scheduler) do\n schedule!(scheduler, now() + Second(1), value)\nend\n\n\n\n\n\n","category":"method"},{"location":"schedulers/#PeaceFounder.Schedulers.waituntil-Tuple{Dates.DateTime}","page":"PeaceFounder.Schedulers","title":"PeaceFounder.Schedulers.waituntil","text":"waituntil(time::DateTime)\n\nWaits until given time is reached. \n\n\n\n\n\n","category":"method"},{"location":"setup/#Setup","page":"Setup","title":"Setup","text":"","category":"section"},{"location":"setup/","page":"Setup","title":"Setup","text":"In the PeaceFounder, communities are referred to as demes. To start a deme, we first need to initialise the cryptographic specification and generate a key for the election authority, which we shall refer to as the guardian. The guardian can further delegate a recorder, recruiter, braider, proposer and collector in the roster recorded in DemeSpec record.","category":"page"},{"location":"setup/#System-Setup","page":"Setup","title":"System Setup","text":"","category":"section"},{"location":"setup/","page":"Setup","title":"Setup","text":"(Image: )","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"The first step to begin using the PeaceFounder e-voting system is to host it, which is a straightforward process on Linux servers. Begin by downloading the snap package with the command below, and remember to change the architecture to arm64 if necessary:","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"curl -LOJ https://github.com/PeaceFounder/PeaceFounderAdmin/releases/download/v0.0.1/peacefounder-server-0.0.1-x64.snap","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"Next, proceed to install the package:","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"snap install --devmode peacefounder-server-0.0.1-x64.snap","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"This installation process automatically handles the compilation and configures the system to start automatically with systemd.","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"The admin panel, accessible at http://127.0.0.1:3221, is hosted locally and is not directly accessible from external networks. To access the admin panel remotely, use SSH to forward the local host port:","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"ssh -L 2332:127.0.0.1:3221 user@192.168.1.16","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"This trick does a secure authentification to the server and is free from PKI network trust assumptions.","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"The admin panel start with a setup wizard, guiding you to select a cryptographic group, choose a hash function, and generate keys. The server generates the guardian key, which is then encrypted with the provided password and stored in the deme record (a feature currently not implemented). Alternatively, you can use the advanced configurator. This option allows for local creation and signing of the deme record, with the option to encrypt the guardian key on the record (also yet to be implemented). The configurator also facilitates server migration, allowing you to input an existing tarball of braidchain records. The deme record is then appended as the last record, enabling continuity (this feature is also pending implementation).","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"Once the wizard is complete, the PeaceFounder server becomes active at http://0.0.0.0:4585. This is the public access point for clients and exposes the REST API. Further configurations, such as setting up an SMTP server to send invitations to prospective members, are done in the Settings panel. Here, you also need to specify an address through which clients can connect to the server. This could be a local address, a public IP, or a DNS pointing to the PeaceFounder REST API.","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"It's important to note that configuring the system doesn't require a TLS certificate for security, as all replies are signed with braidchain and ballotbox tree root commits. Using TLS can be detrimental as it might lower the threshold for making the system vulnerable to DDOS attacks since TLS session resumption has to be disabled to maintain voter anonymity. Each session would require a new key exchange, relying on a relatively costly group operation. Nevertheless, adding TLS currently wouldn't incur additional costs, as HTTP request processing performance is currently not optimised. Furthermore, the PeaceFounder client functions smoothly, even when the server is configured behind NGINX.","category":"page"},{"location":"setup/#Member-Registration","page":"Setup","title":"Member Registration","text":"","category":"section"},{"location":"setup/","page":"Setup","title":"Setup","text":"(Image: )","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"The process of member registration is conducted via email, through which a unique token is dispatched to the user. Unlike JWT tokens, which are typically incorporated into the header of a TLS connection, the token in this system serves a different purpose. It is utilised as a key in the format HMAC(body|timestamp, token) to authenticate requests. To enable the server to identify the origin of the request, a tokenid=Hash(token) is included in the header (currently, ticketid is used but will be made obsolete shortly).","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"When an invite is entered into the PeaceFounder client, the following steps are performed : ","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"The device will retrieve deme specification parameters from the provided address, which will be compared with the hash in the invite;\nThe cryptographic parameters are initialised, and a new key pair is generated;\nThe public key will be authenticated with HMAC using the invite token and will be sent to the deme server, which shall return the public key signed by the registrar, which we shall refer to as the admission certificate;\nIn the last step, the device retrieves the current braidchain generator and computes its pseudonym. This, together with the admission certificate, is signed by the member's private key, which consists of a member certificate. The member certificate is sent to the braidchain until History Tree inclusion proof is received, concluding the process. If the generator has changed, a new pseudonym is recomputed.","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"To guarantee the auditability of the electoral roll, the process involves members signing the received invitations and their corresponding membership certificate record index with a widely trusted digital identity and returning the document to the guardian. This method is robust and effective; the invitation includes a demespec, ensuring that the client has securely interacted with the claimed entity and has used correct cryptographic parameters. Additionally, the member index acts as a confirmation of successful registration. Such a mechanism renders this e-voting system universally adaptable, making it a viable option globally in regions where any form of digital identity infrastructure is in place.","category":"page"},{"location":"setup/#Voting","page":"Setup","title":"Voting","text":"","category":"section"},{"location":"setup/","page":"Setup","title":"Setup","text":"(Image: )","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"The registration of members is followed by the generation of a braid. To boost anonymity, several braids can chained together in sequence. This technique raises the anonymity threshold - the least number of entities required to be breached to associate a member's certificate with their voting pseudonym. Currently, the system supports only self-braiding, setting the maximum anonymity threshold at one. Future updates aim to enable braiding between different demes, which could be either fictional entities created for specific votes or real communities worldwide. The integrity of the final braid receipt is verified using Zero-Knowledge Proofs (ZKPs) and recorded in the braidchain.","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"To initiate voting, the guardian sets up a new proposal. This proposal includes key details such as opening and closing times, title, description, ballot, and an anchor. The anchor is essentially the index of a braid, whose generator and pseudonyms are utilised for the vote. Members registered after the braid’s creation are not included in that particular vote. However, continuous member registration and the ability to self-braid should minimise such exclusions. The anchor also facilitates linking multiple proposals, allowing fluid voting situations where members can alter their votes at predetermined times during a representative’s term.","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"As voting progresses, each vote is logged in the ballot box ledger, displaying the vote cast index, timestamp, sequence number, and vote status. Voters receive a receipt including the timestamp and cast index as a tracking number, which enables them to locate their vote on the bulletin board. The pseudonym links all votes cast from a single device. Plans are underway to introduce an additional token for verifying the vote’s authenticity and a public bulletin board hosted as a static webpage. This will allow voters to ensure their vote is cast as intended and counted accurately.","category":"page"},{"location":"setup/#BraidChain-Ledger","page":"Setup","title":"BraidChain Ledger","text":"","category":"section"},{"location":"setup/","page":"Setup","title":"Setup","text":"(Image: )","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"The BraidChain and BallotBox ledgers together create publicly available proof of election integrity. The BallotBox ledger is straightforward, containing votes signed with the voter's pseudonym without altering the state of the ballot box. In contrast, the BraidChain ledger is more complex, and every record changes the system state. Auditors can run audit commands on records stored in the disk (in development) that require no deep understanding of the underlying data structure. However, in cases where issues arise, having a reference point to communicate about these issues effectively is beneficial.","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"Each record in the BraidChain ledger is authenticated by an issuer's digital signature. To be included, the issuer's record must possess the necessary authorisation, with corresponding public keys detailed in the DemeSpec record, particularly in the roster section. Should there be a need to change a party's key, a revised DemeSpec record is issued, authenticated with the Guardian's private key. It's crucial to secure this key diligently to prevent adversaries from assuming authority and hijacking the election process, which could disrupt availability and create an inconsistent state for participants, leading to the generation of blame proofs. In events where the Guardian's key is compromised, it would necessitate the re-establishment of the deme from scratch. Looking ahead, a potential improvement could involve requiring multiple parties to sign off on the DemeSpec record for it to be valid, thus reducing the likelihood of such breaches.","category":"page"},{"location":"setup/#Developer-Documentation","page":"Setup","title":"Developer Documentation","text":"","category":"section"},{"location":"setup/","page":"Setup","title":"Setup","text":"In this example, the cryptographic parameters are specified in the crypto variable and are further used to initialise the keys on the server for a recruiter, braider, collector and recorder with Mapper.initialize!(crypto) call. The identities are retrieved with Mapper.system_roles() call and are used to fill fields in the DemeSpec record. Afterwards, it is signed by the guardian and is submitted to the server with Mapper.capture!(demespec), which finalises the server configuration, after which the server can be started.","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"import PeaceFounder: Model, Mapper, Service, id, approve\nimport PeaceFounder.Model: TicketID, CryptoSpec, DemeSpec, Signer\nimport HTTP\n\ncrypto = CryptoSpec(\"sha256\", \"EC: P_192\")\n\nGUARDIAN = Model.generate(Signer, crypto)\nPROPOSER = Model.generate(Signer, crypto)\n\nMapper.initialize!(crypto)\nroles = Mapper.system_roles()\n\ndemespec = DemeSpec(; \n uuid = Base.UUID(121432),\n title = \"A local democratic community\",\n crypto = crypto,\n guardian = id(GUARDIAN),\n recorder = roles.recorder,\n recruiter = roles.recruiter,\n braider = roles.braider,\n proposer = id(PROPOSER),\n collector = roles.collector\n) |> approve(GUARDIAN) \n\nMapper.capture!(demespec)\n\nHTTP.serve(Service.ROUTER, \"0.0.0.0\", 80)","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"The second part is to set up the entry for registration within the deme. It is up to the guardian to decide how new members are added to the deme and how their identity is being tracked and made transparent so that members are assured that someone has created fake identities to vote multiple times.","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"
\n \n
Sequence diagram illustrating client registration with a deme. The process begins when the client requests an invitation from the registrar and concludes when a certified pseudonym is submitted to the Braidchain ledger. The protocol serves multiple goals: 1) It simplifies integration by requiring only a hash function for authorization of new member requests. 2) It prevents inconsistencies between the client's device and the braidchain by allowing repetition of the final step. 3) It ensures that registration can continue even when the chain is temporarily locked for new members, by allowing catch-up with the current relative generator. Future updates aim to combine the last two steps to reduce the number of communication rounds required.
\n
","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"That would best be done within the organisation's website, where members can log in and get an invite as a string or QR code scanned in the PeaceFounder client application. To facilitate that, the PeaceFounder service offers a recruiter endpoint from which invites can be obtained and accessed, knowing ROUTE = \"0.0.0.0:80\" and recruiter symmetric key KEY = Mapper.get_recruit_key(). That makes it relatively easy to integrate into the webpage as it only needs the ability to read some JSON and sha256 hash functions used to authenticate and compute registration tokens at the endpoints. That also makes it redundant to add a TLS certificate for the PeaceFoudner service. ","category":"page"},{"location":"setup/#Registrar-setup","page":"Setup","title":"Registrar setup","text":"","category":"section"},{"location":"setup/","page":"Setup","title":"Setup","text":"**Note: This setup part has been deprecated in favour of PeaceFounderAdmin. **","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"
\n \n
A registration form available from Recruiters.jl. When a user puts in his name and email address, a unique invite is automatically sent to the user at the provided email address for registration with the deme.
\n
","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"To make it easier to start using the peacefounder, a simple registrar facade, as shown in the image above, is available in Recruiters.jl. When a user puts in his name and email address, a unique invite is automatically sent to the email with which the user can register. This can also serve as a starting point to make a custom registrar facade and see the involved components, which makes it work. To set it up, we first need to export variables for the deme:","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"export DEME_ROUTE='http://0.0.0.0:80'\nexport DEME_HASHER='sha256'\nexport DEME_RECRUIT_KEY='THE_RECRUIT_KEY'","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"And also for the SMTP service with which recruit emails are going to be sent. This is specified in the following variables:","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"export RECRUIT_SMTP='smtps://mail.inbox.lv:465'\nexport RECRUIT_EMAIL='demerecruit@inbox.lv'\nexport RECRUIT_PASSWORD='THE_EMAIL_PASSWORD'","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"After these environment variables are set, the recruiter service can be started as:","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"using Recruiters\n\ntitle = \"Local Democratic Community\"\npitch = \"\"\"\n

Are you looking for a way to get involved in local politics and make a difference in your community? Do you want to connect with like-minded individuals who share your values and beliefs? If so, we invite you to join our Local Democratic Community.

\n\n

Our community is a group of individuals who are passionate about promoting progressive values and creating positive change in our neighborhoods and towns. We believe that by working together, we can build a more just and equitable society for everyone. As a member of our community, you will have the opportunity to attend events, participate in volunteer activities, and engage in meaningful discussions about the issues that matter most to you.

\n\"\"\"\n\nRecruiters.serve(title, pitch)","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"By default, the serve function reads in the environment variables, but if necessary, those can be specified manually by a set of keyword arguments. See docs for further use of those. ","category":"page"},{"location":"setup/#Braiding","page":"Setup","title":"Braiding","text":"","category":"section"},{"location":"setup/","page":"Setup","title":"Setup","text":"Braiding is a method in which the mix server shuffles input member public keys and raises that to the power of a secret exponent x, resulting in a new set of public keys with relative generator h = g^x. This procedure must be executed honestly, which can be verified with zero-knowledge proofs.","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"In particular, ElGamal re-encryption shuffle is done first on the elements (a b) leftarrow (1 Y_i) for which a zero knowledge of proof compatible with the Verificatum verifier is produced. Then, a proof of decryption for c_i leftarrow b_i^x and h leftarrow g^x is produced. That then is used to calculate the resulting member public keys as Y_i leftarrow ca.","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"In PeaceFounder, this operation can be executed with the following lines of code:","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"input_generator = Mapper.get_generator()\ninput_members = Mapper.get_members()\n\n# This line is executed on an independent mix\nbraidwork = Model.braid(input_generator, input_members, demespec, demespec, Mapper.BRAIDER[]) \nMapper.submit_chain_record!(braidwork)","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"The first demespec contains cryptographic parameters for the group specification for input_generator and input_members. The second demespec is added by the braider, which signs the resulting braid and assures that an independent entity endorsed by a different deme provides assurances to the voter that his vote remains private from the guardian.","category":"page"},{"location":"setup/#Proposal-announcement","page":"Setup","title":"Proposal announcement","text":"","category":"section"},{"location":"setup/","page":"Setup","title":"Setup","text":"A proposal to the PeaceFounder service can be added with a PROPOSER key as follows:","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"commit = Mapper.get_chain_commit()\n\nproposal = Proposal(\n uuid = Base.UUID(23445325),\n summary = \"Should the city ban \\\n all personal automotive vehicle usage?\",\n description = \"\",\n ballot = Ballot([\"yes\", \"no\"]),\n open = Dates.now(),\n closed = Dates.now() + Dates.Second(2),\n collector = roles.collector,\n\nstate = state(commit)\n\n) |> approve(PROPOSER)\n\n\nack = Mapper.submit_chain_record!(proposal) ","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"Notice that state(commit) is added to the proposal. This anchors the relative generator on which the votes are cast.","category":"page"},{"location":"audit/#Audit","page":"Audit","title":"Audit","text":"","category":"section"},{"location":"audit/","page":"Audit","title":"Audit","text":"Note: The demonstrated audit API is in progress and is discussed further in a feature proposal Evidence Auditing with Terminal API. Currently, the best auditing strategy is to recreate the braid chain and ballot box ledger from one record at a time.","category":"page"},{"location":"audit/","page":"Audit","title":"Audit","text":"After elections have ended, the collector publishes a tally. After elections, every voter receives a final tally together with consistency proof, which proves that their vote is included in the ledger that has produced the tally. From the voter client, the voter reads four important parameters for the ballotbox:","category":"page"},{"location":"audit/","page":"Audit","title":"Audit","text":"deme_uuid: a UUID of the deme where the proposal is registered;\nproposal_index: an index at which the proposal is recorded in the braidchain ledger;\nledger_length: a number of collected votes in the ledger;\nledger_root: a ballotbox ledger root checksum.","category":"page"},{"location":"audit/","page":"Audit","title":"Audit","text":"The auditor also knows a hasher deme used to make checksums, which is immutable when the deme is created.","category":"page"},{"location":"audit/","page":"Audit","title":"Audit","text":"To assert the integrity of the vote, an audit takes place. Let's consider abstract functions to retrieve ballotbox and braidchain ledger archives from the internet with get_ballotbox_archive and `getbraidchainarchive; then the auditing can be done with the following script:","category":"page"},{"location":"audit/","page":"Audit","title":"Audit","text":"braidchain_archive = get_ballotbox_archive(uuid)\nballotbox_archive = get_ballotbox_archive(uuid, proposal_index)[1:ledger_length]\n\n@test checksum(ballotbox_archive, hasher) == ledger_root\n@test isbinding(braidchain_archive, ballotbox_archive, hasher)\n\nspec = crypto(braidchain_archive)\n\n@test audit(ballotbox_archive, spec)\n@test audit(braidchain_archive)\n\n@show tally(ballotbox_archive)","category":"page"},{"location":"audit/","page":"Audit","title":"Audit","text":"Note that spec is read from the DemeSpec record in the braidchain, which can be trusted as the tree braidchain ledger checksum is listed within a proposal's anchor. The proposal is the first record in the history tree for the ballotbox; thus, it is bound to the ledger_root checksum, so the demespec record is also tied to ledger_root.","category":"page"},{"location":"audit/","page":"Audit","title":"Audit","text":"For convenience, an audit method is provided that audits both archives at the same time:","category":"page"},{"location":"audit/","page":"Audit","title":"Audit","text":"braidchain_archive = get_ballotbox_archive(uuid)\nballotbox_archive = get_ballotbox_archive(uuid, proposal_index)[1:ledger_length]\n\n@test checksum(ballotbox_archive, hasher) == ledger_root\n@test audit(braidchain_archive, ballotbox_archive, hasher)\n\n@show tally(ballotbox_archive)","category":"page"},{"location":"audit/","page":"Audit","title":"Audit","text":"Note that this audit does not check the honesty of the registrar and that it has not admitted fake users to gain more influence in the election result. Properties being verified by the audit:","category":"page"},{"location":"audit/","page":"Audit","title":"Audit","text":"Legitimacy: only eligible voters cast their votes;\nEquality: every eligible voter can vote at most once;\nImmutability: no vote can be deleted or modified after being recorded in the ledger; \nTallied as Cast: all cast votes are counted honestly according to predetermined procedure; ","category":"page"},{"location":"audit/","page":"Audit","title":"Audit","text":"All these properties together ensure software independence so that the resulting tally does not depend on trust in the honest execution of either peacefounder service or braiders. In other words, the previously listed properties would not be altered if the adversary had full control over the peacefounder service and the braiders. ","category":"page"},{"location":"audit/","page":"Audit","title":"Audit","text":"The immutability is ensured by voter's clients updating their consistency proof chain, which includes their vote. If the vote gets removed from a chain, every voter who cast their vote will get proof for an inconsistent ledger state called blame. The voter can make the blame public without revealing their vote, thus ensuring immutability and persistence after votes are published. The auditable part here is the votes signed with a pseudonym, which contract voters' clients to follow up at later periods with consistency proofs. On top of that, other monitors can synchronise the ballotbox ledger and add assurances that way.","category":"page"},{"location":"model/#PeaceFounder.Core.Model","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model","text":"","category":"section"},{"location":"model/#Primitives","page":"PeaceFounder.Core.Model","title":"Primitives","text":"","category":"section"},{"location":"model/","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model","text":"Modules = [PeaceFounder.Core.Model]\nOrder = [:type, :function]\nPages = [\"Core/Model/crypto.jl\", \"Core/Model/seal.jl\"]","category":"page"},{"location":"model/#PeaceFounder.Core.Model.Commit","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Commit","text":"Commit{T}\n state::T\n seal::Seal\nend\n\nRepresents a commited ledger state to which issuer can be held accountable for integrity. It is assumed that T implements index and root necessaary to fix a ledger state. \n\nInterface: id, issuer, verify, index, root, state\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.CryptoSpec","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.CryptoSpec","text":"struct CryptoSpec\n hasher::HashSpec\n group::GroupSpec\n generator::Generator\nend\n\nSpecification of cryptographic parameters which are used for public key cryptography, message hashing and authetification codes. \n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.Digest","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Digest","text":"struct Digest\n data::Vector{UInt8}\nend\n\nA message digest obtained applying a hash function on a message or a document. See method digest.\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.Generator","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Generator","text":"struct Generator\n data::Vector{UInt8}\nend\n\nDatatype which stores cryptogrpahic group point in standart octet form intended to be used as a base. See also Pseudonym.\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.HMAC","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.HMAC","text":"struct HMAC\n key::Vector{UInt8}\n hasher::HashSpec\nend\n\nRepresent a hash message authetification code authorizer.\n\nInterface: hasher, digest, key\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.Pseudonym","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Pseudonym","text":"struct Pseudonym\n pk::Vector{UInt8}\nend\n\nA datatype which stores public key in canonical standart octet form.\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.Seal","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Seal","text":"struct Seal\n pbkey::Pseudonym\n sig::Signature\nend\n\nA wrapper type for a signature which adds a public key of signature issuer. See seal method. \n\nInterface: pseudonym, verify\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.Signer","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Signer","text":"struct Signer\n spec::CryptoSpec\n pbkey::Pseudonym\n key::BigInt\nend\n\nA signer type. See a method generate(Signer, spec) for initialization.\n\nInterface: pseudonym, id, sign, seal, approve\n\n\n\n\n\n","category":"type"},{"location":"model/#HistoryTrees.root-Tuple{PeaceFounder.Core.Model.Commit}","page":"PeaceFounder.Core.Model","title":"HistoryTrees.root","text":"root(x)::Digest\n\nReturn a ledger root hash.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.digest-Tuple{Any, Any}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.digest","text":"digest(message::Vector{UInt8}, hasher::HashSpec)::Digest\ndigest(document, spec) = digest(canonicalize(message)::Vector{UInt8}, hasher(spec)::HashSpec)\n\nReturn a resulting digest applying hasher on the given message. When message is not octet string a canonicalize method is applied first.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.digest-Tuple{Vector{UInt8}, CryptoGroups.Specs.HashSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.digest","text":"digest(bytes::Vector{UInt8}, hasher::HashSpec)::Digest\ndigest(x, spec) = digest(canonicalize(x)::Vector{UInt8}, hasher(spec)::HashSpec)\n\nCompute a hash digest. When input is not in bytes the canonicalize method is applied first.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.generate-Tuple{Type{PeaceFounder.Core.Model.Signer}, PeaceFounder.Core.Model.CryptoSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.generate","text":"generate(Signer, spec::CryptoSpec)::Signer\n\nGenerate a unique private key and return a Signer object. \n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.generator-Tuple{PeaceFounder.Core.Model.CryptoSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.generator","text":"generator(crypto::CryptoSpec)::Generator\n\nReturn a generator of the specification. \n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.generator-Tuple{Union{CryptoGroups.Specs.ECP, CryptoGroups.Specs.EC2N, CryptoGroups.Specs.Koblitz}}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.generator","text":"generator(spec::Spec)::Generator\n\nReturn a generator of spec.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.hasher-Tuple{PeaceFounder.Core.Model.HMAC}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.hasher","text":"hasher(spec)::HashSpec\n\nAccess a hasher function from a given specification.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.index-Tuple{PeaceFounder.Core.Model.Commit}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.index","text":"index(x)::Int\n\nReturn an index of a ledger state.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.issuer-Tuple{PeaceFounder.Core.Model.Commit}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.issuer","text":"issuer(x)\n\nIn case an object x is cryptographically signed return an issuer of who have issued the signature. See also id.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.key-Tuple{PeaceFounder.Core.Model.HMAC}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.key","text":"key(x)\n\nAccess a secret key of an object x.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.seal-Tuple{Vector{UInt8}, PeaceFounder.Core.Model.Signer}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.seal","text":"seal(message::Vector{UInt8}[, generator::Generator], signer::Signer)::Seal\n\nSign a bytestring message with signer's private key and specification and return a signature as a Seal. When generator is provided it is used as a base for the signature. See also sign.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.sign-Tuple{PeaceFounder.Core.Model.Digest, PeaceFounder.Core.Model.Generator, PeaceFounder.Core.Model.Signer}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.sign","text":"sign(digest::Digest[, generator::Generator], signer::Signer)::Signature\n\nSign a digest as an integer with signer's private key and specification. This method avoids running hashing twice when that is done externally. When generator is provided it is used as a base for the signature.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.sign-Tuple{Vector{UInt8}, PeaceFounder.Core.Model.Generator, PeaceFounder.Core.Model.Signer}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.sign","text":"sign(message::Vector{UInt8}[, generator::Generator], signer::Signer)::Signature\n\nSign a bytestring message with signer's private key and specification. When generator is provided it is used as a base for the signature.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.state-Tuple{PeaceFounder.Core.Model.Commit}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.state","text":"state(commit::Commit{T})::T\n\nReturn a ledger state. T implements index and root. \n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.canonicalize","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.canonicalize","text":"ToDo: a well specified encoding is essential here. Binary tree encoding may suffice here. More fancy approach would be to use a DER encoding. Meanwhile JSON shall be used.\n\n\n\n\n\n","category":"function"},{"location":"model/","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model","text":"PeaceFounder.Core.Model.pseudonym","category":"page"},{"location":"model/#PeaceFounder.Core.Model.pseudonym","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.pseudonym","text":"pseudonym(signer::Signer, [generator])::Pseudonym\n\nReturn a pseudonym of a signer at a given relative generator. If generator is not passed returns identity pseudonym. (See also id)\n\n\n\npseudonym(seal::Seal)::Pseudonym\n\nReturn a pseudonym of a seal. Note that it is not equal to identity when the signature is issued on a relative generator.\n\n\n\npseudonym(vote::Vote)::Pseudonym\n\nReturn a pseudonym used to seal the vote.\n\n\n\n\n\n","category":"function"},{"location":"model/","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model","text":"PeaceFounder.Core.Model.id","category":"page"},{"location":"model/#PeaceFounder.Core.Model.id","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.id","text":"id(document)::Pseudonym\n\nReturn identity pseudonym of a document issuer.\n\n\n\nid(signer)::Pseudonym\n\nReturn identity pseudonym of a signer.\n\n\n\n\n\n","category":"function"},{"location":"model/","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model","text":"PeaceFounder.Core.Model.verify","category":"page"},{"location":"model/#PeaceFounder.Core.Model.verify","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.verify","text":"verify(message, seal::Seal, [generator::Generator], crypto::CryptoSpec)::Bool\nverify(message, pk::Pseudonym, sig::Signature, [generator::Generator], crypto::CryptoSpec)::Bool\n\nVerify the cryptographic signature of the message returning true if valid. An optional generator can be given when signature is issued on a relative generator differing from a base specification crypto. \n\n\n\nverify(document[, generator::Generator], crypto::CryptoSpec)::Bool\n\nVerify a cryptographic signature of the document returning true if valid. \n\n\n\nverify(braidwork::BraidReceipt, crypto::CryptoSpec)::Bool\n\nVerify a braider issued cryptographic signature for the braidwork and a zero knowledge proofs. Returns true if both checks succeed.\n\n\n\n\n\n","category":"function"},{"location":"model/#BraidChain","page":"PeaceFounder.Core.Model","title":"BraidChain","text":"","category":"section"},{"location":"model/","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model","text":"Modules = [PeaceFounder.Core.Model]\nOrder = [:type, :function]\nPages = [\"Core/Model/braidchain.jl\", \"Core/Model/braids.jl\"]","category":"page"},{"location":"model/#PeaceFounder.Core.Model.Admission","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Admission","text":"struct Admission\n ticketid::TicketID\n id::Pseudonym\n timestamp::DateTime\n approval::Union{Seal, Nothing}\nend\n\nRepresents an admission certificate for a pseudonym id. \n\nInterface: approve, issuer, id, ticket, [isadmitted]\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.ChainState","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.ChainState","text":"struct ChainState\n index::Int\n root::Digest\n generator::Generator\n member_count::Int\nend\n\nRepresents a chain state metadata which is sufficient for integrity checks.\n\nInterface: index, root, generator\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.DemeSpec","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.DemeSpec","text":"struct DemeSpec <: Transaction\n uuid::UUID\n title::String\n crypto::CryptoSpec\n guardian::Pseudonym\n recorder::Pseudonym\n registrar::Pseudonym\n braider::Pseudonym\n proposer::Pseudonym \n collector::Pseudonym\n timestamp::Union{DateTime, Nothing} = nothing\n signature::Union{Signature, Nothing} = nothing\nend\n\nRepresents a deme configuration parameters issued by the guardian.\n\nuuid::UUID an unique random generated community identifier;\ntitle::String a community name with which deme is represented;\ncrypto::CryptoSpec cryptographic parameters for the deme;\nguardian::Pseudonym an issuer for this demespec file. Has authorithy to set a roster:\nrecorder::Pseudonym an authorithy which has rights to add new transactions and is responsable for braidchain's ledger integrity. Issues Commit{ChainState};\nregistrar::Pseudonym an authorithy which has rights to authorize new admissions to the deme. See Admission and Membership;\nbraider::Pseudonym an authorithy which can do a legitimate braid jobs for other demes. See BraidReceipt; \nproposer::Pseudonym an authorithy which has rights to issue a proposals for the braidchain. See Proposal;\ncollector::Pseudonym an authorithy which is repsonsable for collecting votes for proposals. This is also recorded in the proposal itself.\ntimestamp::Union{DateTime, Nothing} time when signature is being issued;\nsignature::Union{Signature, Nothing} a guardian issued signature. \n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.Membership","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Membership","text":"struct Membership <: Transaction\n admission::Admission\n generator::Generator\n pseudonym::Pseudonym\n approval::Union{Signature, Nothing} \nend\n\nA new member certificate which rolls in (anouances) it's pseudonym at current generator signed with identity pseudonym certified with admission certificate issued by registrar. This two step process is necessary as a checkpoint in situations when braidchain ledger get's locked during a new member resgistration procedure.\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.TicketID","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.TicketID","text":"struct TicketID\n id::Vector{UInt8}\nend\n\nRepresents a unique identifier for which a recruit tooken is issued. In case of necessity id can contain a full document, for instance, registration form, proof of identity and etc. In case a privacy is an issue the id can contain a unique identifier which can be matched to an identity in an external database.\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.Transaction","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Transaction","text":"Transaction\n\nRepresents an abstract record type which can be stored in the braidchain ledger. \n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.approve-Tuple{PeaceFounder.Core.Model.Admission, PeaceFounder.Core.Model.Signer}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.approve","text":"approve(x::T, signer::Signer)::T\n\nCryptographically sign a document x::T and returns a signed document with the same type. To check whether a document is signed see issuer method.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.approve-Tuple{PeaceFounder.Core.Model.Membership, PeaceFounder.Core.Model.Signer}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.approve","text":"approve(member::Membership, signer::Signer)::Membership\n\nSign a member certificate and return it with approval field filled.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.generator-Tuple{PeaceFounder.Core.Model.Membership}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.generator","text":"generator(member::Membership)::Generator\n\nGenerator at which member tries to roll in the braidchain.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.id-Tuple{PeaceFounder.Core.Model.Membership}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.id","text":"id(member::Membership)::Pseudonym\n\nIdentity pseudonym for a member. \n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.isbinding-Tuple{PeaceFounder.Core.Model.Admission, PeaceFounder.Core.Model.DemeSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.isbinding","text":"isbinding(admission::Admission, spec::DemeSpec)\n\nCheck whether issuer of admission is a registrar set in spec.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.issuer-Tuple{PeaceFounder.Core.Model.Membership}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.issuer","text":"issuer(member::Membership)::Pseudonym\n\nThe identiy of registrar who signed admission.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.members-Tuple{PeaceFounder.Core.Model.BraidChainLedger, Int64}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.members","text":"members(ledger::BraidChainLedger[, index::Int])::Set{Pseudonym}\n\nReturn a set of member pseudonyms at relative generator at braidchain ledger row index. If index is omitted return a current state value.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.pseudonym-Tuple{PeaceFounder.Core.Model.Membership}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.pseudonym","text":"pseudonym(member::Membership)::Pseudonym\n\nPseudonym for a member at the generator(member). \n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.ticket-Tuple{PeaceFounder.Core.Model.Admission}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.ticket","text":"ticket(x::Admission)\n\nReturn a TicketID which is admitted.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.ticket-Tuple{PeaceFounder.Core.Model.Membership}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.ticket","text":"ticket(member::Membership)\n\nTicket for a member admission certificate.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.BraidReceipt","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.BraidReceipt","text":"struct BraidReceipt <: Transaction\n braid::Simulator\n producer::DemeSpec\n approval::Union{Seal, Nothing}\nend\n\nRepresents a braider's computation which is supported with zero knowledge proof of shuffle and decryption assuring it's corectness stored in a braid field; producer denotes a deme where the braid is made. To assert latter the the braider signs the braidwork and stores that in the aproval field. See a braid method.\n\nInterface: approve, verify, input_generator, input_members, output_generator, output_members\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.approve-Tuple{PeaceFounder.Core.Model.BraidReceipt, PeaceFounder.Core.Model.DemeSpec, PeaceFounder.Core.Model.Signer}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.approve","text":"approve(braid::BraidReceipt, spec::DemeSpec, braider::Signer)\n\nSign a braidwork with a braider. Throws an error if braider is not in the producer demespec.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.braid-Tuple{PeaceFounder.Core.Model.Generator, Union{Set{PeaceFounder.Core.Model.Pseudonym}, Vector{PeaceFounder.Core.Model.Pseudonym}}, PeaceFounder.Core.Model.CryptoSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.braid","text":"braid(generator::Generator, members::Union{Vector{Pseudonym}, Set{Pseudonym}}, consumer::DemeSpec, producer::DemeSpec; verifier = (g) -> ProtocolSpec(; g))\n\nSelects a private exponent x at random and computes a new generator g = g^x and member_i=member_i^x returns the latter in a sorted order and provides a zero knowledge proof that all operations have been performed honestly. In partucular, not including/droping new member pseudonyms in the process. consumer attributes are necessary to interepret generator and pseudonym group elements with which the computation is performed. \n\nBy default a Verificatum compatable verifier is used for performing reencryption proof of shuffle\n\nA verifier can be configured with a keyword argument. By default a Verificatum compatable verifier for a proof of shuffle is used.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.input_generator-Tuple{PeaceFounder.Core.Model.BraidReceipt}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.input_generator","text":"input_generator(braid::BraidReceipt)\n\nReturn input generator of the braid.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.input_members-Tuple{PeaceFounder.Core.Model.BraidReceipt}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.input_members","text":"input_members(braid::BraidReceipt)\n\nReturn input member pseudonyms of the braid at provided input generator. See input_generator\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.output_generator-Tuple{PeaceFounder.Core.Model.BraidReceipt}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.output_generator","text":"output_generator(braid::BraidReceipt)\n\nReturn output genertor of the braid.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.output_members-Tuple{PeaceFounder.Core.Model.BraidReceipt}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.output_members","text":"output_members(braid::BraidReceipt)\n\nReturn output member pseudonyms of the braid at a resulting output generator. See output_generator\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.verify-Tuple{PeaceFounder.Core.Model.BraidReceipt, PeaceFounder.Core.Model.CryptoSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.verify","text":"verify(braid::BraidReceipt, crypto::CryptoSpec)\n\nVerifies a braid approval and then it's zero knowledge proofs. A crypto argument is provided to avoid downgrading attacks. \n\n\n\n\n\n","category":"method"},{"location":"model/#Ballot-Box","page":"PeaceFounder.Core.Model","title":"Ballot Box","text":"","category":"section"},{"location":"model/","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model","text":"Modules = [PeaceFounder.Core.Model]\nOrder = [:type, :function]\nPages = [\"Core/Model/ballotbox.jl\"]","category":"page"},{"location":"model/#PeaceFounder.Core.Model.Ballot","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Ballot","text":"struct Ballot\n options::Vector{String}\nend\n\nRepresents a simple ballot form for multiple choice question. \n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.BallotBoxState","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.BallotBoxState","text":"struct BallotBoxState\n proposal::Digest\n seed::Digest\n index::Int\n root::Digest\n tally::Union{Nothing, Tally} \n view::Union{Nothing, BitVector} # \nend\n\nRepresents a public ballot box state. Contains an immutable proposal and seed digest; a current ledger index, history tree root. When ellections end a tally is included in the state and a view is added listing all counted votes. Note that the view attribute is important for a client to know whether it's key have leaked and somone lese havbe superseeded it's vote by revoting.\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.CastReceipt","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.CastReceipt","text":"struct CastReceipt\n vote::Digest\n timestamp::DateTime\nend\n\nRepresents a ballotbox ledger receipt which is hashed for a history tree. It's sole purpose is to assure voters that their vote is included in the ledger while also adding additional metadata as timestamp and. In contrast to CastRecord it does not reveal how voter have voted thus can be published during ellections without violating fairness property. For some situations it may be useful to extend the time until the votes are published as that can disincentivice coercers and bribers as they would not know whether their coerced vote have been superseeded in revoting. See receipt method for it's construction from a CastRecord.\n\nNote that a blind signature could be commited as H(signature|H(vote)) to avoid tagging the use of pseudonym during ellections while collector could issue only a one blind signature for a voter. Note that members whoose private key could have been stolen could not obtain a valid signature for participation and that could be a good thing!\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.CastRecord","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.CastRecord","text":"struct CastRecord\n vote::Vote\n timestamp::DateTime\nend\n\nRepresents a ballotbox ledger record. Adds a timestamp when the vote have been recorded. In future, the record will also contain a blind signature with which members could prove to everyone that they had cast their vote without revealing the link to the vote.\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.Proposal","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Proposal","text":"struct Proposal <: Transaction \n uuid::UUID\n summary::String\n description::String\n ballot::Ballot\n open::DateTime\n closed::DateTime\n collector::Union{Pseudonym, Nothing} # \n anchor::Union{ChainState, Nothing}\n approval::Union{Seal, Nothing} \nend\n\nRepresents a proposal for a ballot specyfing voting window, unique identifier, summary, description. Set's the collector identity which collects votes and issues vote inclusion receipts and is responsable for maintaining the ledger's integrity. The proposal also includes an anchor which sets a relative generator with which members vote anonymously. To be considered valid is signed by proposer authorizing vote to take place.\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.Selection","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Selection","text":"struct Selection\n option::Int\nend\n\nRepresents voter's selection for a Ballot form.\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.Tally","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Tally","text":"struct Tally\n data::Vector{Int}\nend\n\nRepresent a tally for Ballot form obtained aftert counting multiple voter's Selection forms.\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.Vote","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Vote","text":"struct Vote\n proposal::Digest\n seed::Digest\n selection::Selection\n seq::Int\n approval::Union{Seal, Nothing} \nend\n\nRepresents a vote for a proposal issued by a member. The proposal is stored as hash digest ensuring that member have voted on an untampered proposal. seed contains a randon string issued by collector at the moment when a vote starts to eliminate early voting / shortening a time at which coercers could act uppon. selection contians voter's preference; \n\nseq is a serquence number counting a number of votes at which vote have been approved for a given proposal. It starts at 1 and is increased by one for every single signature made on the proposal. This is an important measure which allows to detect possible leakage of a member's private key. Also provides means for revoting ensuring that latest vote get's counted.\n\nThe vote is considered valid when it is sealed by a member's private key at a relative generator stored in the proposal. \n\n\n\n\n\n","category":"type"},{"location":"model/#HistoryTrees.root-Tuple{PeaceFounder.Core.Model.BallotBoxState}","page":"PeaceFounder.Core.Model","title":"HistoryTrees.root","text":"root(state::BallotBoxState)\n\nReturn a history tree root for a current ballotbox ledger state.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.generator-Tuple{PeaceFounder.Core.Model.Proposal}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.generator","text":"generator(proposal::Proposal)\n\nA relative generator for at which memebers sign votes for this proposal.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.index-Tuple{PeaceFounder.Core.Model.BallotBoxState}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.index","text":"index(state::BallotBoxState)\n\nReturn an index for a current ballotbox ledger state.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.isbinding-Tuple{PeaceFounder.Core.Model.CastReceipt, PeaceFounder.Core.Model.Vote, CryptoGroups.Specs.HashSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.isbinding","text":"isbinding(receipt::CastReceipt, vote::Vote, hasher::HashSpec)::Bool\n\nCheck that the receipt is bidning to a vote. \n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.isbinding-Tuple{PeaceFounder.Core.Model.Vote, PeaceFounder.Core.Model.Proposal, CryptoGroups.Specs.HashSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.isbinding","text":"isbinding(vote::Vote, proposal::Proposal, crypto::HashSpec)\n\nCheck that the vote is bound to a proposal.. \n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.isconsistent-Tuple{PeaceFounder.Core.Model.Selection, PeaceFounder.Core.Model.Ballot}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.isconsistent","text":"isconsistent(selection::Selection, ballot::Ballot)\n\nVerifies that voter's selection is consistent with ballot form. For instance, whether selection is withing the range of ballot options.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.issuer-Tuple{PeaceFounder.Core.Model.Proposal}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.issuer","text":"issuer(proposal::Proposal)\n\nIssuer of approval for the proposal.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.pseudonym-Tuple{PeaceFounder.Core.Model.Vote}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.pseudonym","text":"pseudonym(vote::Vote)::Union{Pseudonym, Nothing}\n\nReturn a pseudonym with which vote is sealed.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.receipt-Tuple{PeaceFounder.Core.Model.CastRecord, CryptoGroups.Specs.HashSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.receipt","text":"receipt(record::CastRecord, hasher::HashSpec)::CastReceipt\n\nConstruct a CastReceipt from a CastRecord with a provided hasher function.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.state","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.state","text":"state(ledger::BallotBoxLedger; seed::Digest, root::Digest = root(ledger), with_tally::Union{Nothing, Bool} = nothing)::BallotBoxState\n\nReturn a state metadata for ballotbox ledger. \n\n\n\n\n\n","category":"function"},{"location":"model/#PeaceFounder.Core.Model.state-Tuple{PeaceFounder.Core.Model.Proposal}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.state","text":"state(proposal::Proposal)::ChainState\n\nA braidchain ledger state which is used to anchor a relative generator for members.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.tally","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.tally","text":"tally(ledger::BallotBox)\n\nCompute a tally for a ballotbox ledger. \n\n\n\n\n\n","category":"function"},{"location":"model/#PeaceFounder.Core.Model.tally-Tuple{PeaceFounder.Core.Model.Ballot, AbstractVector{PeaceFounder.Core.Model.Selection}}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.tally","text":"tally(ballot::Ballot, ballots::AbstractVector{Selection})::Tally\n\nCount ballots, check that they are filled consistently and return a final tally.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.uuid-Tuple{PeaceFounder.Core.Model.Proposal}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.uuid","text":"uuid(proposal::Proposal)::UUID\n\nUUID for a proposal. Issued by proposer and it's purpose is to croslink to an external system durring the proposal dreafting stage.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.vote-Tuple{PeaceFounder.Core.Model.Proposal, PeaceFounder.Core.Model.Digest, PeaceFounder.Core.Model.Selection, PeaceFounder.Core.Model.Signer}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.vote","text":"vote(proposal::Proposal, seed::Digest, selection::Selection, member::Signer; seq = 1)\n\nIssue a vote on a proposal and provided collector seed for a member's selection. \n\n\n\n\n\n","category":"method"},{"location":"model/#Auditing","page":"PeaceFounder.Core.Model","title":"Auditing","text":"","category":"section"},{"location":"model/","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model","text":"Modules = [PeaceFounder.Core.Model]\nOrder = [:type, :function]\nPages = [\"Core/Model/audit.jl\"]","category":"page"},{"location":"model/#PeaceFounder.Core.ProtocolSchema","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.ProtocolSchema","text":"","category":"section"},{"location":"model/","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model","text":"Modules = [PeaceFounder.Core.ProtocolSchema]\nOrder = [:type, :function]","category":"page"},{"location":"model/#PeaceFounder.Core.ProtocolSchema.AckConsistency","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.ProtocolSchema.AckConsistency","text":"struct AckConsistency{T}\n proof::ConsistencyProof\n commit::Commit{T}\nend\n\nRepresents an ackknowledgment from the issuer that a root is permanetly included in the ledger. This acknowledgemnt assures that ledger up to index(ack) is included in the current ledger which has has index index(commit(ack)). This is useful in a combination with AckInclusion to privatelly update it's validity rather than asking an explicit element. Also ensures that other elements in the ledger are not being tampered with.\n\nInterface: root, id, issuer, commit, index, verify\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.ProtocolSchema.AckInclusion","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.ProtocolSchema.AckInclusion","text":"struct AckInclusion{T}\n proof::InclusionProof\n commit::Commit{T}\nend\n\nRepresents an acknowldgment from the issuer that a leaf is permanently included in the ledger. In case the ledger is tampered with this acknowledgement acts as sufficient proof to blame the issuer.\n\nInterface: leaf, id, issuer, commit, index, verify\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.ProtocolSchema.CastAck","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.ProtocolSchema.CastAck","text":"struct CastAck\n receipt::CastReceipt\n ack::AckInclusion{BallotBoxState}\nend\n\nRepresents a reply to a voter when a vote have been included in the ballotbox ledger. Contains a receipt and inlcusion acknowledgment. In future would also include a blind signature in the reply for a proof of participation. To receive this reply (with a blind signature in the future) a voter needs to send a vote which is concealed during ellections and thus tagging votes with blind signatures from reply to monitor revoting would be as hard as monitoring the submitted votes.\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.ProtocolSchema.TicketStatus","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.ProtocolSchema.TicketStatus","text":"struct TicketStatus ticketid::TicketID timestamp::DateTime admission::Union{Nothing, Admission} end\n\nRepresents a public state of a ticket. See isadmitted method. \n\n\n\n\n\n","category":"type"},{"location":"model/#HistoryTrees.leaf-Tuple{PeaceFounder.Core.ProtocolSchema.AckInclusion}","page":"PeaceFounder.Core.Model","title":"HistoryTrees.leaf","text":"leaf(ack::AckInclusion)\n\nAccess a leaf diggest for which the acknowledgment is made.\n\n\n\n\n\n","category":"method"},{"location":"model/#HistoryTrees.root-Tuple{PeaceFounder.Core.ProtocolSchema.AckConsistency}","page":"PeaceFounder.Core.Model","title":"HistoryTrees.root","text":"root(x::AckConsistency)\n\nAccess a root diggest for which the acknowledgment is made.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.commit-Tuple{PeaceFounder.Core.ProtocolSchema.AckInclusion}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.commit","text":"commit(x)\n\nAccess a commit of an object x. \n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.commit-Tuple{PeaceFounder.Core.ProtocolSchema.CastAck}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.commit","text":"commit(ack::CastAck)\n\nReturn a commit from a CastAck.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.index-Tuple{PeaceFounder.Core.ProtocolSchema.AckConsistency}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.index","text":"index(ack::AckConsistency)\n\nReturn an index for a root at which the consistency proof is made. To obtain the current ledger index use index(commit(ack)).\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.index-Tuple{PeaceFounder.Core.ProtocolSchema.AckInclusion}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.index","text":"index(ack::AckInclusion)::Int\n\nReturn an index at which the leaf is recorded in the ledger. To obtain the current ledger index use index(commit(ack)).\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.isbinding-Tuple{PeaceFounder.Core.Model.CastReceipt, PeaceFounder.Core.ProtocolSchema.AckInclusion, CryptoGroups.Specs.HashSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.isbinding","text":"isbinding(receipt::CastReceipt, ack::AckInclusion, hasher::HashSpec)::Bool\n\nCheck that cast receipt is binding to received inclusion acknowledgment.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.isbinding-Tuple{PeaceFounder.Core.Model.Transaction, PeaceFounder.Core.ProtocolSchema.AckInclusion{PeaceFounder.Core.Model.ChainState}, PeaceFounder.Core.Model.CryptoSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.isbinding","text":"isbinding(record::Transaction, ack::AckInclusion{ChainState}, crypto::CryptoSpec)\n\nA generic method checking whether transaction is included in the braidchain.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.isbinding-Tuple{PeaceFounder.Core.ProtocolSchema.CastAck, PeaceFounder.Core.Model.Proposal, CryptoGroups.Specs.HashSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.isbinding","text":"isbinding(ack::CastAck, proposal::Proposal, hasher::HashSpec)::Bool\n\nCheck that acknowledgment is legitimate meaning that it is issued by a collector listed in the proposal.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.verify-Tuple{PeaceFounder.Core.ProtocolSchema.CastAck, PeaceFounder.Core.Model.CryptoSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.verify","text":"verify(ack::CastAck, crypto::CryptoSpec)::Bool\n\nVerify the cast acknowledgment cryptographic signature. \n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.ProtocolSchema.isadmitted-Tuple{PeaceFounder.Core.ProtocolSchema.TicketStatus}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.ProtocolSchema.isadmitted","text":"isadmitted(status::TicketStatus)\n\nCheck whether ticket is addmitted. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers","text":"","category":"section"},{"location":"controllers/#Registrar","page":"PeaceFounder.Server.Controllers","title":"Registrar","text":"","category":"section"},{"location":"controllers/","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers","text":"Modules = [PeaceFounder.Server.Controllers]\nOrder = [:type, :function]\nPages = [\"Server/Controllers/registrar.jl\"]","category":"page"},{"location":"controllers/#PeaceFounder.Server.Controllers.Registrar","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.Registrar","text":"struct Registrar\n metadata::Ref{Vector{UInt8}} \n tickets::Vector{Ticket}\n signer::Signer\n hmac::HMAC\nend\n\nRepresents a state for token registrar service. To initialize the service it's necessary to create a signer who can issue a valid admisssion certificates and a secret key with which a recruit client can exchange authorized messages. See also method generate(Registrar, spec).\n\nMetadata is used as means to securelly deliver to the client most recent server specification. \n\nInterface: select, hmac, hasher, key, id, tickets, in, enlist!, admit!, isadmitted, ticket_status\n\n\n\n\n\n","category":"type"},{"location":"controllers/#PeaceFounder.Server.Controllers.Ticket","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.Ticket","text":"mutable struct Ticket\n const ticketid::TicketID\n timestamp::DateTime\n attempt::UInt8\n token::Digest\n tokenid::String # \n admission::Union{Admission, Nothing}\nend\n\nRepresents a ticket state for ticket with ticketid. timestamp represents time when the ticket have been issued by a registrar client in authorization system of choice, for instance, Registrars.jl; attempt is a counter with which token can be reset which is calculated with token(ticketid, attempt, hmac). Lastly admission contains a certified member pseudonym which was authetificated by the user with token.\n\n\n\n\n\n","category":"type"},{"location":"controllers/#Base.in-Tuple{PeaceFounder.Core.Model.TicketID, PeaceFounder.Server.Controllers.Registrar}","page":"PeaceFounder.Server.Controllers","title":"Base.in","text":"in(ticketid::TicketID, registrar::Registrar)::Bool\n\nReturn true if there already is a ticket with ticketid.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.generate-Tuple{Type{PeaceFounder.Server.Controllers.Registrar}, PeaceFounder.Core.Model.CryptoSpec}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.generate","text":"generate(Registrar, spec::CryptoSpec)\n\nGenerate a new token registrar with unique signer and athorization key.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.select-Tuple{Type{PeaceFounder.Core.Model.Admission}, PeaceFounder.Core.Model.Pseudonym, PeaceFounder.Server.Controllers.Registrar}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.select","text":"select(Admission, ticketid::TicketID, registrar::Registrar)::Union{Admission, Nothing}\n\nReturn admission for a ticket with given a given identity pseudonym from registrar. If no ticket with given id is found OR ticket is not yet admitted returns nothing.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.select-Tuple{Type{PeaceFounder.Core.Model.Admission}, PeaceFounder.Core.Model.TicketID, PeaceFounder.Server.Controllers.Registrar}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.select","text":"select(Admission, ticketid::TicketID, registrar::Registrar)::Union{Admission, Nothing}\n\nReturn admission for a ticket with given ticketid from registrar. If no ticket with given ticketid is found OR ticket is not yet admitted returns nothing.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.select-Tuple{Type{PeaceFounder.Server.Controllers.Ticket}, Function, PeaceFounder.Server.Controllers.Registrar}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.select","text":"select(T, predicate::Function, registrar::Registrar)::Union{T, Nothing}\n\nFrom a list of all registrar tickets return T <: Union{Ticket, Admission} for which predicate is true. If none succeds returns nothing.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.ProtocolSchema.isadmitted-Tuple{PeaceFounder.Core.Model.TicketID, PeaceFounder.Server.Controllers.Registrar}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.ProtocolSchema.isadmitted","text":"isadmitted(ticketid::TicketID, registrar::Registrar)\n\nCheck whether a ticket is already admitted. Returns false when either ticket is nonexistent or it's admission is nothing.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.admit!-Tuple{PeaceFounder.Server.Controllers.Registrar, PeaceFounder.Core.Model.Pseudonym, PeaceFounder.Core.Model.TicketID}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.admit!","text":"admit!(registrar::Registrar, id::Pseudonym, ticketid::TicketID)::Admission\n\nAttempt to admit an identity pseudonym id for ticket ticketid. Authorization is expected to happen at the service layer using provided token in the invite. If a ticket is already registered return admission if it matches the provided id. Otherwise throe an error.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.enlist!-Tuple{PeaceFounder.Server.Controllers.Registrar, PeaceFounder.Core.Model.TicketID, Dates.DateTime}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.enlist!","text":"enlist!(registrar::Registrar, ticketid::TicketID, timestamp::DateTime; route::URI=registrar.route)::Invite\n\nRegisters a new ticket with given TicketID and returns an invite. If ticket is already registered the same invite is returned. Throws an error when ticket is already registered.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.hmac-Tuple{PeaceFounder.Server.Controllers.Registrar}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.hmac","text":"hmac(x)::HMAC\n\nReturn HMAC authorizer from a given object.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.set_demehash!-Tuple{PeaceFounder.Server.Controllers.Registrar, PeaceFounder.Core.Model.Digest}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.set_demehash!","text":"set_demespec!(registrar::Registrar, spec::Union{Digest, DemeSpec})\n\nReplace metadata for a registrar. Note when data is replaced all unfinalized tokens need to be flushed. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.ticket_status-Tuple{PeaceFounder.Core.Model.TicketID, PeaceFounder.Server.Controllers.Registrar}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.ticket_status","text":"ticket_status(ticketid::TicketID, registrar::Registrar)::Union{TicketStatus, Nothing}\n\nReturn a ticket status for a ticketid. In case ticket is not found return nothing.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.tickets-Tuple{PeaceFounder.Server.Controllers.Registrar}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.tickets","text":"tickets(registrar::Registrar)::Vector{TicketID}\n\nReturn a list of registered ticket ids. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.token-Tuple{PeaceFounder.Core.Model.TicketID, UInt8, CryptoGroups.Specs.HashSpec, Vector{UInt8}}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.token","text":"token(ticketid::TicketID, hmac::HMAC)\n\nCompute a recruit token for a given ticketid. Calculates it as token=Hash(Hash(0|key)|attempt|ticketid) where attempt is a counter for which token is issued.\n\nNote: the token generation from key is made in order to support it's local computation on a remote server where QR code for registration is shown within organization website.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#BraidChain","page":"PeaceFounder.Server.Controllers","title":"BraidChain","text":"","category":"section"},{"location":"controllers/","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers","text":"Modules = [PeaceFounder.Server.Controllers]\nOrder = [:type, :function]\nPages = [\"Server/Controllers/braidchain.jl\"]","category":"page"},{"location":"controllers/#PeaceFounder.Server.Controllers.BraidChainController","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.BraidChainController","text":"struct BraidChain\n members::Set{Pseudonym}\n ledger::BraidChainLedger\n spec::DemeSpec\n generator::Generator\n tree::HistoryTree\n commit::Union{Commit{ChainState}, Nothing}\nend\n\nRepresents a braidchain ledger with it's associated state. Can be instantitated with a demespec file using BraidChain(::DemeSpec) method.\n\nInterface: push!, record!, state, length, list, select, roll, constituents, generator, commit, commit_index, ledger, leaf, root, ack_leaf, ack_root, members, commit!\n\n\n\n\n\n","category":"type"},{"location":"controllers/#Base.push!-Tuple{PeaceFounder.Server.Controllers.BraidChainController, PeaceFounder.Core.Model.Transaction}","page":"PeaceFounder.Server.Controllers","title":"Base.push!","text":"push!(ledger::BraidChainController, t::Transaction)\n\nAdd an element to the BraidChainController bypassing transaction verification with the chain. This should only be used when the ledger is loaded from a trusted source like a local disk or when final root hash is validated with a trusted source.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#HistoryTrees.leaf-Tuple{PeaceFounder.Server.Controllers.BraidChainController, Int64}","page":"PeaceFounder.Server.Controllers","title":"HistoryTrees.leaf","text":"leaf(ledger::BraidChainController, N::Int)::Digest\n\nReturn a ledger's element digest at given index.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#HistoryTrees.root-Tuple{PeaceFounder.Server.Controllers.BraidChainController}","page":"PeaceFounder.Server.Controllers","title":"HistoryTrees.root","text":"root(ledger::BraidChainController[, N::Int])::Digest\n\nReturn a ledger root digest. In case when index is not given a current index is used.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.commit-Tuple{PeaceFounder.Server.Controllers.BraidChainController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.commit","text":"commit(ledger::BraidChainController)\n\nReturn a current commit for a braichain. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.generator-Tuple{PeaceFounder.Server.Controllers.BraidChainController, Int64}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.generator","text":"generator(ledger[, index])\n\nReturn a generator at braidchain ledger row index. If index is omitted return the current state value.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.generator-Tuple{PeaceFounder.Server.Controllers.BraidChainController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.generator","text":"generator(ledger::BraidChainController)\n\nReturn a current relative generator for a braidchain ledger.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.isbinding-Tuple{PeaceFounder.Server.Controllers.BraidChainController, PeaceFounder.Core.Model.ChainState}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.isbinding","text":"isbinding(chain::BraidChainController, state::ChainState)::Bool\n\nCheck that chain state is consistent with braidchain ledger.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.members-Tuple{PeaceFounder.Server.Controllers.BraidChainController, Int64}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.members","text":"members(chain::BraidChainController, [n::Int])::Set\n\nReturn a set of member pseudonyms which at given anchor index can participate in voting or braiding.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.select-Union{Tuple{T}, Tuple{Type{T}, Function, PeaceFounder.Server.Controllers.BraidChainController}} where T<:PeaceFounder.Core.Model.Transaction","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.select","text":"select(T, predicate::Function, ledger::BraidChainController)::Union{T, Nothing}\n\nReturn a first element from a ledger with a type T which satisfies a predicate. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.state-Tuple{PeaceFounder.Server.Controllers.BraidChainController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.state","text":"state(ledger::BraidChainController)\n\nReturn a current braidchain ledger state metadata.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.ack_leaf-Tuple{PeaceFounder.Server.Controllers.BraidChainController, Int64}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.ack_leaf","text":"ack_leaf(ledger::BraidChainController, index::Int)::AckInclusion\n\nReturn a proof for record inclusion with respect to a current braidchain ledger history tree root. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.ack_root-Tuple{PeaceFounder.Server.Controllers.BraidChainController, Int64}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.ack_root","text":"ack_root(ledger::BraidChainController, index::Int)\n\nReturn a proof for the ledger root at given index with respect to the current braidchain ledger history tree root.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.commit!-Tuple{PeaceFounder.Server.Controllers.BraidChainController, PeaceFounder.Core.Model.Signer}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.commit!","text":"commit!(ledger::BraidChainController, signer::Signer)\n\nCommit a current braidchain ledger state with a signer's issued cryptographic signature. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.constituents-Tuple{PeaceFounder.Server.Controllers.BraidChainController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.constituents","text":"constituents(ledger::BraidChainController)::Set{Pseudonym}\n\nReturn all member identity pseudonyms. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.list-Union{Tuple{T}, Tuple{Type{T}, PeaceFounder.Server.Controllers.BraidChainController}} where T<:PeaceFounder.Core.Model.Transaction","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.list","text":"list(T, ledger::BraidChainController)::Vector{Tuple{Int, T}}\n\nList braidchain elements with a given type together with their index.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.reset_tree!-Tuple{PeaceFounder.Server.Controllers.BraidChainController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.reset_tree!","text":"reset_tree!(ledger::BraidChainController)\n\nRecompute a chain tree hash. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.roll-Tuple{PeaceFounder.Server.Controllers.BraidChainController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.roll","text":"roll(ledger::BraidChainController)::Vector{Membership}\n\nReturn all member certificates from a braidchain ledger.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#BallotBox-and-PollingStation","page":"PeaceFounder.Server.Controllers","title":"BallotBox and PollingStation","text":"","category":"section"},{"location":"controllers/","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers","text":"Modules = [PeaceFounder.Server.Controllers]\nOrder = [:type, :function]\nPages = [\"Server/Controllers/ballotbox.jl\"]","category":"page"},{"location":"controllers/#PeaceFounder.Server.Controllers.BallotBoxController","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.BallotBoxController","text":"mutable struct BallotBoxController\n ledger::BallotBoxLedger\n voters::Set{Pseudonym} # better than members\n collector::Pseudonym\n seed::Union{Digest, Nothing}\n queue::Vector{Vote}\n tree::HistoryTree\n commit::Union{Commit{BallotBoxState}, Nothing}\nend\n\nRepresents a ballot box for a proposal. Contains proposal, a set of eligiable voters a collector who collects the votes and a seed which is selected at random when the voting starts. queue contains a list of valid votes which yet to be comitted to a ledger. A history tree is built on leafs of ledger's receipts (see a receipt method). A commit contains a collector seal on the current ballotbox state. \n\nInterface: reset_tree!, generator, uuid, ledger, spine, index, seed, leaf, root, receipt, commit, tally, set_seed!, ack_leaf, ack_root, ack_cast, commit_index, commit_state, push!, state, validate, record!, commit!\n\n\n\n\n\n","category":"type"},{"location":"controllers/#PeaceFounder.Server.Controllers.PollingStation","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.PollingStation","text":"struct PollingStation\n halls::Vector{BallotBoxController}\n crypto::CryptoSpec\nend\n\nRepresents a pooling station which hosts ballotbox ledgers for every proposal collector manages. \n\nInterface: init!, record!, commit!, commit, ack_leaf, ack_root, ack_cast, receipt, spine, ledger, tally, set_seed!\n\n\n\n\n\n","category":"type"},{"location":"controllers/#Base.get-Tuple{PeaceFounder.Server.Controllers.PollingStation, Base.UUID}","page":"PeaceFounder.Server.Controllers","title":"Base.get","text":"get(station::PollingStation, uuid::UUID)::BallotBoxController\n\nReturn a ballotbox ledger with a provided UUID. If none is found throws an error.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#Base.get-Tuple{PeaceFounder.Server.Controllers.PollingStation, PeaceFounder.Core.Model.Digest}","page":"PeaceFounder.Server.Controllers","title":"Base.get","text":"get(station::PollingStation, proposal::Digest)::BallotBoxController\n\nReturn a ballotbox which has proposal with provided digest.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#Base.getindex-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, Int64}","page":"PeaceFounder.Server.Controllers","title":"Base.getindex","text":"getindex(ledger::BallotBoxController, index::Int)::CastRecord\n\nReturn a ledger record at provided index.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#Base.length-Tuple{PeaceFounder.Server.Controllers.BallotBoxController}","page":"PeaceFounder.Server.Controllers","title":"Base.length","text":"length(ledger::BallotBoxController)\n\nReturn a total length of the ledger including uncommited records in the queue.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#Base.push!-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, PeaceFounder.Core.Model.CastRecord}","page":"PeaceFounder.Server.Controllers","title":"Base.push!","text":"push!(ledger::BallotBoxController, record::CastRecord)\n\nPush a record to the ledger bypassing integrity checks. Used when loading the ledger from a trusted source such as local disk or an archive with a signed root cheksum.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#HistoryTrees.leaf-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, Int64}","page":"PeaceFounder.Server.Controllers","title":"HistoryTrees.leaf","text":"leaf(ledger::BallotBoxController, N::Int)::Digest\n\nReturn a record digest used to form a history tree.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#HistoryTrees.root-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, Int64}","page":"PeaceFounder.Server.Controllers","title":"HistoryTrees.root","text":"root(ledger::BallotBoxController[, N::Int])::Digest\n\nCalculate a root for history tree at given index N. If index is not specified returns the current value.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.commit-Tuple{PeaceFounder.Server.Controllers.BallotBoxController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.commit","text":"commit(ledger::BallotBoxController)\n\nReturn a commit for the ballotbox ledger.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.commit-Tuple{PeaceFounder.Server.Controllers.PollingStation, Base.UUID}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.commit","text":"commit(station::PollingStation, uuid::UUID)::Commit\n\nReturn a ballotbox commit.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.generator-Tuple{PeaceFounder.Server.Controllers.BallotBoxController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.generator","text":"generator(ledger::BallotBoxController)\n\nReturn a relative generator which members use to sign votes anchored by the proposal.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.index-Tuple{PeaceFounder.Server.Controllers.BallotBoxController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.index","text":"index(ledger::BallotBoxController)\n\nReturn the current index of the ledger. See also length.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.isbinding-Tuple{PeaceFounder.Core.Model.Vote, PeaceFounder.Core.ProtocolSchema.CastAck, PeaceFounder.Core.Model.CryptoSpec}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.isbinding","text":"isbinding(vote::Vote, ack::CastAck, hasher)\n\nCheck whether acknowledgment is bound to the provided vote.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.receipt-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, Int64}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.receipt","text":"receipt(ledger::BallotBoxController, index::Int)::CastReceipt\n\nReturn a receipt for a ledger element.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.receipt-Tuple{PeaceFounder.Server.Controllers.PollingStation, Base.UUID, Int64}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.receipt","text":"receipt(station::PollingStation, uuid::UUID, N::Int)::CastReceipt\n\nReturn a receipt for a record with index N at ballotbox with uuid.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.seed-Tuple{PeaceFounder.Server.Controllers.BallotBoxController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.seed","text":"seed(ledger::BallotBoxController)::Union{Digest, Nothing}\n\nReturn a random selected seed used in the voting.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.tally-Tuple{PeaceFounder.Server.Controllers.PollingStation, Base.UUID}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.tally","text":"tally(station::PollingStation, uuid::UUID)\n\nCompute a tally from ledger records a ballotbox with uuid.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.uuid-Tuple{PeaceFounder.Server.Controllers.BallotBoxController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.uuid","text":"uuid(ledger::BallotBoxController)\n\nReturn a UUID of the proposal.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.voters-Tuple{PeaceFounder.Server.Controllers.BallotBoxController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.voters","text":"voters(ledger::BallotBoxController)\n\nReturn a list of member pseudonyms with which members authetificate their votes.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.ack_cast-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, Int64}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.ack_cast","text":"ack_cast(ledger::BallotBoxController, index::Int)::CastAck\n\nCompute an acknowledgment for record inclusion at index.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.ack_cast-Tuple{PeaceFounder.Server.Controllers.PollingStation, Base.UUID, Int64}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.ack_cast","text":"ack_cast(station::PollingStation, uuid::UUID, N::Int)::CastAck\n\nReturn inclusion proof with receipt and current tree commit for a leaf at index N and ballotbox with uuid. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.ack_leaf-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, Int64}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.ack_leaf","text":"ack_leaf(ledger::BallotBoxController, index::Int)::AckInclusion\n\nCompute an inclusion proof ::AckInclusion for record element at given index.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.ack_leaf-Tuple{PeaceFounder.Server.Controllers.PollingStation, Base.UUID, Int64}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.ack_leaf","text":"ack_leaf(station::PollingStation, uuid::UUID, N::Int)::AckInclusion\n\nReturn history tree inclusion proof for a tree leaf at index N in ballotbox with uuid.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.ack_root-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, Int64}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.ack_root","text":"ack_root(ledger::BallotBoxController, index::Int)::AckConsistency\n\nCompute a history tree consistency proof at index. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.ack_root-Tuple{PeaceFounder.Server.Controllers.PollingStation, Base.UUID, Int64}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.ack_root","text":"ack_root(station::PollingStation, uuid::UUID, N::Int)::AckConsistency\n\nReturn history tree consitency proof tree root at index N in ballotbox with uuid.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.commit!-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, Dates.DateTime, PeaceFounder.Core.Model.Signer}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.commit!","text":"commit!(ledger::BallotBoxController[, timestamp::DataTime], signer::Signer; with_tally=nothing)\n\nFlushes ballotbox ledger's queue and creates a commit for a current ballotbox ledger state with provided timestamp and signer. A keyword argument with_tally has three values true|false to include or exclude a tally from a commited state and nothing which uses a previous commit preference.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.commit!-Tuple{PeaceFounder.Server.Controllers.PollingStation, Base.UUID, PeaceFounder.Core.Model.Signer}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.commit!","text":"commit!(station::PollingStation, uuid::UUID, collector::Signer; with_tally = nothing)\n\nSelect a ballotbox with provided uuid and commit it's state with collector. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.commit_index-Tuple{PeaceFounder.Server.Controllers.BallotBoxController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.commit_index","text":"commit_index(ledger::BallotBoxController)::Union{Index, Nothing}\n\nIndex at which commit is issued. See also length and index\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.commit_state-Tuple{PeaceFounder.Server.Controllers.BallotBoxController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.commit_state","text":"commit_state(ledger::BallotBoxController)\n\nReturn a committed state for a ballotbox ledger.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.init!-Tuple{PeaceFounder.Server.Controllers.PollingStation, PeaceFounder.Core.Model.DemeSpec, PeaceFounder.Core.Model.Proposal, Vector{PeaceFounder.Core.Model.Pseudonym}, PeaceFounder.Core.Model.Pseudonym}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.init!","text":"init!(station::PollingStation, proposal::Proposal, voters::Set{Pseudonym}[, collector::Pseudonym])\n\nCreates a new ballotbox for given proposal with provided member pseudonyms at a relative generator anchored in the proposal. A collector is optional and provided only when it differs from one specified in the proposal. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.ledger-Tuple{PeaceFounder.Server.Controllers.BallotBoxController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.ledger","text":"ledger(ballotbox::BallotBoxController)::Vector{CastRecord}\n\nReturn all records from a ballotbox ledger.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.ledger-Tuple{PeaceFounder.Server.Controllers.PollingStation, Base.UUID}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.ledger","text":"ledger(station::PollingStation, uuid::UUID)::Vector{CastRecord}\n\nReturn a vector of records from a ballotbox with uuid.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.record!-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, PeaceFounder.Core.Model.CastRecord}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.record!","text":"record!(ledger::BallotBoxController, record::CastRecord)\n\nCheck the vote in the record for validity and include that in the ledger directly bypassing queue. This method is useful for replaying and debugging ballotbox ledger state changes. See also record!\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.record!-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, PeaceFounder.Core.Model.Vote}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.record!","text":"record!(ledger::BallotBoxController, vote::Vote)\n\nCheck the vote for validity and pushes it to the queue. Returns an index N at which the vote will be recorded in the ledger. See also push!\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.record!-Tuple{PeaceFounder.Server.Controllers.PollingStation, Base.UUID, PeaceFounder.Core.Model.Vote}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.record!","text":"record!(station::PollingStation, uuid::UUID, vote::Vote)::Int\n\nRecords a vote in a ballotbox with provided proposal UUID. Throws an error if a ballotbox can't be found.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.record!-Tuple{PeaceFounder.Server.Controllers.PollingStation, PeaceFounder.Core.Model.Vote}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.record!","text":"record!(station::PollingStation, uuid::UUID, vote::Vote)::Int\n\nRecord a vote in a ballotbox found by proposal diggest stored in the vote. Throws an error if a ballotbox can't be found.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.reset_tree!-Tuple{PeaceFounder.Server.Controllers.BallotBoxController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.reset_tree!","text":"reset_tree!(ledger::BallotBoxController)\n\nRecompute history tree root and cache from the elements in the ledger. This is a useful for loading the ledger all at once. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.set_seed!-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, PeaceFounder.Core.Model.Digest}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.set_seed!","text":"set_seed!(ledger::BallotBoxController, seed::Digest)\n\nSet's a seed of the ballotbox.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.set_seed!-Tuple{PeaceFounder.Server.Controllers.PollingStation, Base.UUID, PeaceFounder.Core.Model.Digest}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.set_seed!","text":"set_seed!(station::PollingStation, uuid::UUID, seed::Digest)\n\nSets a seed for a ballotbox with provided uuid.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.spine-Tuple{PeaceFounder.Server.Controllers.BallotBoxController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.spine","text":"spine(ledger::BallotBoxController)::Vector{Digest}\n\nReturn a history tree leaf vector.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.spine-Tuple{PeaceFounder.Server.Controllers.PollingStation, Base.UUID}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.spine","text":"spine(station::PollingStation, uuid::UUID)::Vector{Digest}\n\nReturn a leaf vector for a ballotbox with proposal uuid.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.validate-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, PeaceFounder.Core.Model.Vote}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.validate","text":"validate(ledger::BallotBoxController, vote::Vote)\n\nCheck that vote can be included in the ballotbox. Is well formed, signed by a member pseudonym and cryptographic signature is valid. Raises error if either of checks fail.\n\n\n\n\n\n","category":"method"},{"location":"client/#Client","page":"Client","title":"Client","text":"","category":"section"},{"location":"client/","page":"Client","title":"Client","text":"The PeaceFounder client can be installed on all major desktop platforms by simply downloading a bundle for your particular platform from the PeaceFounderClient release page. Currently, for demonstration purposes, the application does not save a state. Also, errors should be appropriately handled. For instance, receiving an incorrect receipt or proof from the bulletin board will crash the application. This will be solved in future versions of the client.","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"In the future, the focus will be on mobile applications for iOS and Android. Unfortunately, in the current state, deploying mobile applications with Julia is not possible due to JIT compilation. This is why the client backend is planned to be rewritten in Rust while keeping the QML facade already written. This will be a significant time investment; thus, I would be eager to test the PeaceFounder voting system in practice with the desktop GUI client only to gauge people's needs.","category":"page"},{"location":"client/#For-Developers","page":"Client","title":"For Developers","text":"","category":"section"},{"location":"client/","page":"Client","title":"Client","text":"The PeaceFounder client is implemented in a QML and is available on all major desktop platforms. To run the client, install a recent Julia version on your computer, clone a https://github.com/PeaceFounder/PeaceFounderGUI repository, and run the GUI application with the following:","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"julia --load main.jl","category":"page"},{"location":"client/#Registration-to-a-Deme","page":"Client","title":"Registration to a Deme","text":"","category":"section"},{"location":"client/","page":"Client","title":"Client","text":"The first step for the peacefounder voting system as a potential voter is to enrol in a deme. A deme is an organisational body that maintains the electoral roll of its members and puts proposals to members for a vote. After the person has enrolled and become a member, they can access proposals. It is, however, crucial that only proposals announced after the member registration are available for a vote as the registered member's pseudonym needs to be anonymised first through braiders with other members[1]. ","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"[1]: This could be amended in future versions of the PeaceFounder if this becomes a significant dealbreaker for usability. In such a scenario, a member who registers late would sign votes with their identity pseudonym, and the votes could be tallied together with pseudonymously signed ones but never published on the bulletin board. ","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"
\n \n
Left: an example invite email sent by the Recruiters.jl service. Right: PeaceFounder QML client application at the home screen where the invite can be used to register as member to the Deme. On mobile, a QR code could be scanned instead.
\n
","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"The registration procedure starts with requesting an invite. The invite can be requested from an organisation website, which could show it on the screen, or it can be sent to the email as shown in the figure above. The invite is then scanned in the PeaceFounder client application, which does heavy registration work - generates private and public key pairs, spends an assigned token, authorises the public key, and gets a corresponding admission certificate, which finally is used to catch up with a current relative generator and issue a member certificate which is submitted to the braidchain for inclusion. Since the invite contains a hash digest of the demespec file, registration can be performed under an unsecured channel, making TLS certificate setup redundant for the PeaceFounder service.","category":"page"},{"location":"client/#Voting-on-a-proposal","page":"Client","title":"Voting on a proposal","text":"","category":"section"},{"location":"client/","page":"Client","title":"Client","text":"The member’s identity is represented as a row index in the braidchain storing the member record. This avoids presenting users with overwhelming public keys and lets them grasp their registration status. It also indicates to the voter the minimum anchor index at which the new member can vote on the proposal.","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"
\n \n
Left: a deme view where member’s identity is 21 and the current braidchain state is 89. Two proposals are listed with different states. Right: A selected proposal view. This time, it is not votable by the member as the proposal anchor is 4, whereas the member index is 21. (Images need to be updated for consistency)
\n
","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"When a voter enters the proposal within the specified time window, it can go to ballot view by pressing Vote Now. The ballot view depends on the kind of Ballot used in the proposal. Since the votes are plaintext messages signed with pseudonyms, there are unlimited types of ballots that PeaceFounder can support, like - cardinal, preferential or budget-constrained ballots, some of which are planned to be implemented in the future.","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"A guard report is shown to the voter when the vote is cast. The guard contains three categories:","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"Ballot Box: the deme UUID and a proposal’s record index on the braidchain, after which the elections can be found online.\nA receipt contains the pseudonym hash with which the vote is being cast, the timestamp on when it was recorded in the ballot box, and the cast record gives an index at which the vote is recorded in the ledger.\nA commit contains a current Merkle tree root and index of the collector signed chain. This is also an index at which consistency proof is being checked so that votes can only be removed from the ballot box after they are added with evidence.","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"
\n \n
Left: a view for multiple question ballot. Right: a guard view where the voter sees ballot box identifier, a receipt for casting a vote and a commit of the current state of the ballot box.
\n
","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"The Merkle tree inclusion and consistency proof as a receipt to make a tamper-resistant bulletin board monitored by voters. So that undesirable votes can not be discarded when they have been recorded.","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"After the elections, each voter's client device checks whether the last cast vote is included in the final tally, together with a sequence number on the vote that prevents an adversary that has obtained the voter's private key from casting votes on voters' behalf without being noticed. This is done automatically as long as the client's device acts honestly, i.e., is not infected with malware.","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"In the case of malware, the fairness property maintained by the election authority and a timestamp on the casting receipt prevent malware on the voter's client from pointing to a substitute vote. Whereas the vote is cast as intended and counted as cast (important for revoting), a voter can check on the bulletin board with another computer using the receipt. If the malware is detected, the voter takes appropriate action for his device.","category":"page"},{"location":"schema/#HTTP-API","page":"HTTP","title":"HTTP API","text":"","category":"section"},{"location":"schema/","page":"HTTP","title":"HTTP","text":"\n\n\n\n
\n","category":"page"},{"location":"assets/registration_sequence/","page":"-","title":"-","text":"sequenceDiagram\n participant Client\n participant Registrar\n participant PeaceFounder\n Client->>Registrar: Requests an invite\n Registrar->>PeaceFounder: {ticket_id}_key\n PeaceFounder->>Registrar: {ticket_id, timestamp, demespec, salt}_key\n Registrar->>Client: ticket_id, demespec, token\n Client ->> PeaceFounder: {ticket_id, member_id}_token\n PeaceFounder ->> Client: {member_id}_registrar\n Client ->> PeaceFounder: {pseudonym}_member\n PeaceFounder ->> Client: inclusion_proof, {chain_state}_recorder","category":"page"},{"location":"overview/#Overview","page":"Overview","title":"Overview","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"Note: a more recent and condensed overview is provided in a poster presented at EVoteID 2023","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"
\n \n
A knot like structure formed in a braiding process. On the left, inputs are shown a set of pseudonyms and a relative generator $g$. On the right, the outputs are shuffled pseudonyms, and relative generator exponentiated with a secret factor $s$. The knot itself represents a zero knowledge proof assuring that output pseudonyms are computed correctly without allowing to link input to output pseudonyms. Since $h=g^s$ then $(g^{x_i})^s = (g^s)^{x_i} = h^{x_i}$ which can be computed by private key $x_i$ owners.
\n
","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The core primitive for the PeaceFounder voting system revolves around the ability to generate digital signatures using a single private key for distinct generators, all while maintaining the security of the key. The signatures in such cases are supplemented with a corresponding public key for a relative generator at which the signature has been issued. A relationship between these public keys can be established by showing an exponent connecting the relative generators or forming zero-knowledge proof demonstrating the equality of discrete logarithms. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The concept of unlinkability can be harnessed to create an interconnected structure using multiple private keys resembling a knot. In this structure, input pseudonyms—public keys derived by exponentiating input relative generator with private keys—are bound to output pseudonyms. To achieve this, a dealer exponentiates a relative generator and pseudonyms with the same secret exponent and then shuffles the resulting output pseudonym list. We shall refer to this procedure as braiding to distinguish that from mixing objectives where input retains the original form after going through a mix cascade. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"To ensure integrity in resulting braids, in particular, that braider had not replaced output pseudonyms with its own, zero-knowledge proofs can be used. This can be done by reformulating exponentiation as ElGamal re-encryption shuffle and consequent decryption as recently proposed in a novel e-voting system design. The zero-knowledge proof of shuffle has been successfully made widely available for ElGamal re-encryption mixnets with Verificatum, which offers proof with relatively standard cryptographic assumptions on the difficulty of computing discrete logarithms and a decisional Diffie Hellman assumption. Combined with zero knowledge proof of correct decryption, a braid proof can be formed, proving to everyone that computations have been performed honestly without revealing the secret exponentiation factor braider had used and can be safely forgotten afterwards. The resulting braid primitive is available in the ShuffleProofs.jl package, which also reimplements Verificatum-compatible proof of shuffle in Julia. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The braid primitive enables anonymisation to be transactional with one braider at a time, thus eliminating the need for complex coordination of parties as it is typical for many re-encryption mixnet or homomorphic-based e-voting systems. In addition, it's also possible to publish this evidence on a bulletin board for everyone to verify without compromising participation privacy.","category":"page"},{"location":"overview/#Bulletin-Board","page":"Overview","title":"Bulletin Board","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"
\n \n
High-level diagram of the PeaceFounder system. With a blue colour, the internal components of the peacefounder system are indicated, which are necessary to bootstrap the system. The arrows represent dependencies for producing trust in the election process. Services like TOR and DRAND are shown for context and currently are not integrated.
\n
","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The PeaceFounder's bulletin board is a microservice that accepts transactional records and votes. The primary transactional records include member certificates issued in prospective member interaction with the registrar, braid records which recompute pseudonym member list and corresponding relative generator issued by a braider and proposal records announcing a vote issued by a proposer. The system is configured with a guardian issued deme[1] record, which sets cryptographic parameters, and a rooster, which includes the proposer, registrar, and bulletin board authority identities. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"[1]: The term deme here denotes a PeaceFounder instance for a specific organisation. It is inspired by its historical significance in Ancient Greece, where a deme represented a local administrative unit with its own diverse decision-making structure and governance rules.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The peacefounder bulletin board, proposer, and registrar microservices are internal and can be managed or delegated by a guardian. This separation accommodates customisation for varied political consensus, criteria for proposal submissions to the ballot box, choice of identity provider, and methods for disclosing registrar information to auditors to verify the authenticity of members. To make testing and deployment easier for new organisations, a bundle that includes a registrar, proposer and bulletin board will be available and deployable on a preferred server of choice and will offer web access for a guardian with sane defaults and configuration options.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Member's client devices actively monitor the bulletin board, ensuring the immutability of records by tracking bulletin board commits. This method of oversight is scalable, as members only request a history tree[2] consistency proofs, eliminating the need to replicate the actual bulletin board records. These proofs guarantee the protection of their votes and others, assuring that modifications to records are prevented when fresh entries are appended to the bulletin board. This streamlined approach enables prompt identification of bulletin board dishonesty, whether through removing or altering records or the malicious creation of a counterfeit ledger to exclude undesirable votes from the official tally.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"[2]: A history tree is a specialised Merkle tree designed to track chronological changes, enabling efficient and secure state verification at any historical point.","category":"page"},{"location":"overview/#Auditing","page":"Overview","title":"Auditing","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"Integral to establishing trust, a pivotal role is the presence of an {\\bf auditor}. The auditor is a judicial-like entity representing members and is vital for resolving conflicts. Member client devices create local proofs for altered or removed records or the presence of a counterfeit ledger, which are then sent to the auditor. Moreover, if votes aren't delivered, the auditor can act as a proxy, offering evidence that the bulletin board deliberately omitted specific votes. The auditor also ensures the integrity of the bulletin board's records, confirming each vote's eligibility and unlinkability and ensuring one vote per member.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Notably, the auditor can avoid a formal association with the guardian to verify the integrity of a resulting tally, as all relevant data is on the public bulletin board (except for the registration roll). This autonomy allows members the freedom to select their trusted auditors. If there are unresolved disputes with the bulletin board, members can even take on the auditor role and, if necessary, seek to replace the guardian. The system's transparency further allows auditors to cross-check each other's findings, promoting accuracy and preventing the spread of false claims.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The auditor plays a key role in assessing the registrar to confirm the authenticity of its members. The registrar maintains a registration roll, serving as evidence of every member's authenticity. Authenticity verification can be as simple as a trusted third party's digital signature on a document that includes the organisation's UUID and the index where a member's certificate is recorded. If a third-party identity provider isn't available, a photo or video of an individual displaying a page with the organisation's title and index might suffice. Regardless of the method, the recommended approach is to provide an auditor with a verifiably random subset of members where verifiable randomness, for instance, can be generated with DRAND service to avoid data aggregation.","category":"page"},{"location":"overview/#Coercion-and-bribery-resistance","page":"Overview","title":"Coercion and bribery resistance","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"
\n \n
Illustration of time restricted receipt freeness in the Peacefounder voting system. During the election period, the system maintains both receipt-freeness and fairness. However, after the tally is published, newly submitted votes lose their fairness. The votes themselves can be published on the buletin board latter to extend the time period for receipt-freeness, reducing the effectiveness of coercers and bribers. This comes at the expense of delaying the audit process for verifying that votes have been tallied as cast.
\n
","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Another pillar that is necessary for ensuring democratic elections is to prevent coercion and vote buying. A significant risk to the PeaceFounder system is for a briber to ask members to forward their votes through a proxy channel they control. To counter this threat, the bulletin board hides the actual votes, showing only their hashes, and gives voters an option to revote, ensuring both receipt freeness and vote fairness. A sequence number along the vote ensures that only the latest cast vote on the device matters. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"This method undermines the confidence of vote buyers and coercers, as it prevents them from ensuring that the votes they've acquired will be counted in the final tally. As a consequence, they can only return bribes after votes are published on the bulletin board. (During the vote, only receipt hashes are published on the bulletin board. This serves to both commit the votes while maintaining fairness and receipt-freeness.) This arrangement erodes the credibility of bribers and coercers, making it less likely for voters to engage with them in such transactions due to the lack of a guaranteed positive/negative outcome.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"A secondary concern is the potential for a coercer to ask an individual to show how they had voted on their device. To address this, only a receipt is shown. However, this receipt can be linked to the specific vote on the bulletin board. If coercion becomes a significant threat, the receipt can be visible only briefly, such as 30 minutes after casting a vote. During this window, members can manually record their details in a logbook. While this approach may reduce user-friendliness, it still serves as a robust deterrent against malware.","category":"page"},{"location":"overview/#Malware-and-spyware-detection","page":"Overview","title":"Malware and spyware detection","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"(Image: A PICTURE WITH A RECEIPT)","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The last piece of the puzzle is malware and spyware resistance. An adversary could issue votes without compromising the voter's device in case of key leakage. To counter this, every vote includes a sequence number, which records evidence on the bulletin board when a vote is cast from the voter's device. Moreover, if a vote with a sequence number of one is already on the ledger, the first will override any subsequent vote with the same sequence number. This mechanism prevents malware from silently replacing inactive voter's choices. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"After voting concludes and the results are published, each voter receives a bitmask of the votes included in the final tally, along with consistency proofs. Given that this approach is scalable (e.g., 1kB can handle 8192 votes, and bit compression can further reduce size), voters device's compare this bitmask with the index from their most recent vote receipt. This allows them to detect any malware activity and display an alert to the voter.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"To ensure the voting process's integrity, the voter's device must remain trustworthy. With the presence of malware, there's a risk that the device could falsely reassure the voter that their vote is cast as intended. To counter this threat, after the vote is submitted, the voter receives a receipt containing a timestamp of the vote's record, the pseudonym under which it was cast, and the index where the vote resides on the ledger. Once voting concludes and all votes are disclosed on the bulletin board, the voter can cross-reference their receipt with the bulletin board, verifying that the vote at the provided index aligns with their choice and matches the timestamp when the vote was cast, as well as checking that it was included in the final tally. By maintaining a written record, voters can ensure the accuracy of their vote, safeguarding against malware alterations, unauthorised revoting, or any attempts to redirect multiple voters to a singular vote. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"However, it's essential to acknowledge that voters can only detect malware interference post-vote when comparing their receipt to the bulletin board. Additionally, a voter cannot provide evidence to others that their vote was compromised by malware, which means these instances aren't audited within the PeaceFounder system. As a result, members are encouraged and are responsible for utilising more secure devices less susceptible to malware attacks. For more advanced threats, like a briber mandating malware installation for monitoring or extracting the master key, the use of tamper-resistant hardware becomes essential – an extension larger organisations or states might consider.","category":"page"},{"location":"overview/#Implementation-details-and-responsibilities","page":"Overview","title":"Implementation details and responsibilities","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"(Image: )","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"To illustrate the responsibilities of different entities and the structure of the communication channels, we've provided a detailed diagram. In this representation, arrows indicate which entity holds responsibility for specific resources. The primary mode of communication is facilitated through JSON within an HTTP request/reply. The JSON is also chosen as a canonical byte string format for data signing, which is selected over the ASN1 DER format due to development resource constraints.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The architecture bifurcates the bulletin board into two distinct ledgers: the braidchain and the ballot boxes. This differentiation arises from the disparate pacing and metadata requirements of records. Additionally, casting votes remains inconsequential to the braidchain's state, justifying the ledger division.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Authorised entities, namely the braidchain recorder and the ballot box collector, as specified in the guardian-issued DemeSpec record, oversee each ledger. These controllers uphold the integrity of newly added records, ensuring their coherence with the existing state. For instance, votes must adhere to a specified time window and need to be appropriately signed with member pseudonyms. Braidchain transactions demand more intricate state management, which will be described later. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"In the diagram, arrows necessitating anonymous channels are designated with a TOR label originating from the member. This is a countermeasure against potential adversaries attempting to link votes to members via IP addresses. Although alternative network anonymising solutions exist, TOR is the most prominent, and together with the recent release of the Arti project for Rust, it is ideal for client-side applications [...].","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Members can view the bulletin board records through the HTTP Facade, which displays them in a browser-friendly HTML. This provides a secondary channel to verify that votes are cast as intended and counted as cast. A pure JavaScript-based HTTP facade is possible, which can be hosted on a static website, simplifying deployment. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"It's imperative to recognise the absence of TLS in all communications. This choice stems from the fact that data from the bulletin board is supported with a signature on Merkle tree root, rendering requests tamper-proof. Moreover, using TLS session resumption for anonymous interactions between members and the bulletin board would unintentionally make the system vulnerable to DDOS attacks during the key establishment phase. Furthermore, eliminating the need for certificate issuance and management streamlines system maintenance and deployment, enhancing usability.","category":"page"},{"location":"overview/#Planed-Core-Features","page":"Overview","title":"Planed Core Features","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"The PeaceFounder system is actively focusing on integrating key features in its upcoming iterations to enhance transparency. While not exhaustive, the current list includes well-defined proposals ready for implementation.","category":"page"},{"location":"overview/#PeaceFounderBB","page":"Overview","title":"PeaceFounderBB","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"https://github.com/PeaceFounder/PeaceFounder.jl/issues/22","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"A small democratic community often faces the challenge of limited resources, particularly when it comes to hosting bulletin board data or maintaining a comprehensive website for public record access. However, a recent trend offers a practical solution with static website hosting platforms. These platforms allow the creation of a static website directly from source code stored in a git repository without the hassle of setting up and managing certificates. A popular example is GitHub Pages, which simplifies deployment using action scripts to compile websites from sources.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Integrating a GitHub workflow to compile a webpage makes it an ideal platform for hosting a bulletin board interface. This setup has a dual advantage. The GitHub repository can serve as an authentic storage space for bulletin board records. Secondly, these records are easily accessible to the public via a web interface. Continuous integration further enhances this with build scripts, ensuring the integrity and verification of the bulletin board's contents. Those interested in verifying the bulletin board's integrity independently can either fork the repository and run the action script or clone the data locally.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Additionally, the use of the Zenodo repository enriches this system. Zenodo provides excellent archival workflows and the capability to generate a DOI link. This link serves a similar purpose to dataset references in scientific research, offering a reliable and citable record.","category":"page"},{"location":"overview/#Cast-as-intended-verification-during-the-vote","page":"Overview","title":"Cast as intended verification during the vote","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"https://github.com/PeaceFounder/PeaceFounder.jl/issues/21","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"At present, voters can only confirm that their vote has been cast as intended and accurately counted after the vote has ended and the votes are published. As the publication of votes can be delayed as a measure against coercion, it might discourage voters' participation from verifying that their vote is indeed cast as intended and counted as cast. The key issue lies in the possibility of unnoticed malware on voting devices. If voters don't verify their votes, the likelihood of malware affecting a significant number of votes without detection increases. Thus, having a procedure that enables immediate verification of the voting process is essential to engage more voters to check their votes.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The PeaceFounder system can address this by providing voters with a token displayed on the client's screen for vote verification. This token can be used in a web browser to confirm that the vote has been cast as intended. It also indicates if the vote has been superseded by a subsequent vote or one with a higher sequence number, which may occur if the member's key is compromised. To maintain receipt-freeness, the token remains valid for only a short period, such as 15 minutes. The expiration is crucial; it allows voters to verify their votes while preventing coercion or bribery attempts. It also hinders any unsolicited checks on voters' choices.","category":"page"},{"location":"overview/#Evidence-auditing-with-terminal-API","page":"Overview","title":"Evidence auditing with terminal API","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"https://github.com/PeaceFounder/PeaceFounder.jl/issues/19","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The PeaceFounder system is universally verifiable, a feature ensuring that every vote is cryptographically proven to come from a registered member, even if all involved parties are corrupt. To mitigate the influence of coercion or bribery, the authority can strategically delay the publication of votes, which weakens the link between coercers and their subjects before the voters lose receipt freeness. After the votes are published, every aspect of the voting process is transparent: all proofs of votes are made publicly available. This transparency allows any interested party to audit the election results and, at their convenience, independently reproduce the announced tally.","category":"page"},{"location":"overview/#Membership-Termination","page":"Overview","title":"Membership Termination","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"https://github.com/PeaceFounder/PeaceFounder.jl/issues/18","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Under the current state of PeaceFounder, administrators face a significant limitation: they lack the capability to terminate memberships. This function is crucial in various scenarios. For instance, when a member fails to submit necessary authenticity documents within the allotted time post-registration, their membership must be annulled. Additionally, this feature is vital for addressing privacy concerns, such as when members wish to withdraw and have their associated records deleted. Furthermore, an essential aspect of membership management involves issuing new credentials in cases where a member loses their device or experiences a security breach with their key being compromised.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The process of terminating a membership in PeaceFounder presents its own set of challenges. The core difficulty lies in the inability to link a member's real identity and their current pseudonym, which prevents the removal of it in subsequent braidings. This link is only known exclusively to the member's client device, as it only knows the private key that can generate them.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"A straightforward approach to address this issue involves resetting the generator in the braidchain and taking identity pseudonyms of the membership certificates as inputs to subsequent braidings. However, this method presents a significant hurdle, particularly for larger organisations. Implementing this reset each time a member is terminated can be prohibitively expensive. In particular, taking into account that the frequency of membership termination cases increases proportionally with the number of members as well as the required compute to do braidings, making this approach to scale as O(N^2). Therefore, a more sophisticated and nuanced solution is needed.","category":"page"},{"location":"overview/#Extensions","page":"Overview","title":"Extensions","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"In order to avoid over-commitment, the peacefounder project currently focuses on smaller-scale organisations. This implies that a single developer must be able to maintain the system, that coercion/bribery is not of the utmost importance, and that the electoral roll is not necessary to satisfy the requirements of a law. Thus, those features are not integrated into the current design and can be considered separately as system extensions.","category":"page"},{"location":"overview/#Proof-of-participation","page":"Overview","title":"Proof of participation","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"https://github.com/PeaceFounder/PeaceFounder.jl/issues/12","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Some communities may wish to nudge their members to vote, providing benefits for those who have already cast a vote or punishing those who ignore democratic decision-making. In ordinary e-voting systems, that can be easily achieved through a voter’s registry. However, this is not possible for PeaceFounder because voters are completely anonymous when they cast a vote.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"One way to address this issue is with a blind signature scheme. The voter takes his identity pseudonym, blinds it with a random factor and includes that in the vote when sent to the ballot box. The collector checks that the vote is valid and, if so, signs the blinded group element at the time when the vote is recorded in the ledger. The blind signature is reused if the voter has already cast a ballot.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The voter then receives an acknowledgement that the vote is permanently recorded in the chain together with the blind signature and timestamp. The voter unblinds the blind signature with its blinding factor and obtains a signature on his identity pseudonym as proof of participation. That can then be safely shown publicly for anyone who wants to see that the person has voted without being linked to the cast vote.","category":"page"},{"location":"overview/#Selection's-asymmetric-encryption","page":"Overview","title":"Selection's asymmetric encryption","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"https://github.com/PeaceFounder/PeaceFounder.jl/issues/16","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"To maintain the impartiality of auditors/monitors with regard to votes they oversee and further deter potential bribery attempts, an asymmetric encryption method for vote selection is advisable. Under this protocol, the voter's device encrypts a symmetric key asymmetrically and then proceeds to encrypt the vote selection using this symmetric key. The key and the encrypted selection are included in the vote, which is then signed using a pseudonym. Upon receiving the vote, after authenticating its signature, the system decrypts the symmetric key, followed by the vote selection. To ensure the decryption's integrity, a zero-knowledge proof is provided and subsequently published alongside the vote on the bulletin board.","category":"page"},{"location":"overview/#Coerced-vote-tagging","page":"Overview","title":"Coerced vote tagging","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"https://github.com/PeaceFounder/PeaceFounder.jl/issues/16","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"A threat where coercers forcibly dictate voters' choices while confiscating their devices is a pressing concern beyond the PeaceFounder system. A common solution to such a problem is equipping voters with an option to create a secondary PIN code, which works exactly as the primary PIN code except that the votes are tagged as coerced. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"To safeguard against coercers potentially discerning this distinction using a proxy vote submission method, the coercion tag can be asymmetrically encrypted as a group element before transmitting it to the ballot box collector. Upon receipt, the collector would record and then decrypt the coercion tag. A zero-knowledge proof of decryption would ensure the collector's integrity, published together with a vote on the bulletin board. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Votes are disclosed at the conclusion of the process, indicating any tags applied. By lengthening the gap between the tally announcement and the release of the votes, we can diminish the impact of coercive threats and deter unscrupulous voters from awaiting compensation, hinging on the assumption of the briber's credibility. Technically, this mechanism ensures receipt freeness until they appear on the ballot box ledger.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"This strategy presumes that no adversarial entity has infiltrated the collector system. To mitigate such risks, deploying multiple collectors, to which voters are randomly pre-assigned, is advised. This introduces a level of inter-collector accountability, as aggregated results should align. Notably, while receipt freeness is limited, the method retains full transparency: all parties can validate the tally's accuracy and verify every vote's eligibility and unlinkability, as well as the validity of the coercion tag. ","category":"page"},{"location":"overview/#Sempled-Electoral-Roll-Audits","page":"Overview","title":"Sempled Electoral Roll Audits","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"https://github.com/PeaceFounder/PeaceFounder.jl/issues/17","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"In order to ensure the integrity of elections, it is crucial that independent auditors audit the legitimacy of members. However, the records that support the membership cannot be made public as it would violate the members' right to freedom of association and would also infringe on GDPR. Keeping these records confidential while ensuring they are sufficiently audited can be challenging and may require reducing openness to prevent any possible leaks.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"To overcome this dilemma in favour of more openness, a sampling of the electoral roll could be used. A large enough sample size can provide sufficient confidence that a potentially corrupt registrar could not have affected the election result, whereas keeping it small reduces the impact of leaks from the auditors. This lowers the trust barrier and opens the electoral roll auditing for more independent parties.","category":"page"},{"location":"overview/#Early-leaked-private-key-detection","page":"Overview","title":"Early leaked private key detection","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"In a situation where the adversary has acquired a member's private key, they can form valid votes that can be included in the bulletin board. To detect that a bitmask is included in the ballot box commit, which the voter retrieves together with consistency proofs. That allows us to see whether tallied votes have been cast from the member's device as it can look into the bitmask for tallied votes after the vote. However, when a member votes after the adversary, the bulletin board could inform about the fact in the receipt.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The problem is that showing on receipt whether the vote is a final submission considered for inclusion in the tally can impede the voter's ability to revote if the coercer/briber waits until the last minute before submitting their acquired vote. This circumvents a measure where publishing votes is delayed for an extended time after the tally is published for eroding trust in bribers and delaying punishment from coercers. Therefore, the response status needs to be asymmetrically encrypted. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The status code can be encrypted as a group element and decrypted on the voter's device. If the submitted vote is not final, the collector encrypts a group element representing status addressed to the pseudonym that cast the vote. The device receives the receipt, and as it only has the private key, the status code can be shown. That allows members to see early whether the vote was already cast with the provided sequence number and superseded it with possible recasting. ","category":"page"},{"location":"overview/#Sharded-Ballots","page":"Overview","title":"Sharded Ballots","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"In democratic processes, it's conceivable that voters may be presented with an extensive list of ballot questions to express their opinions. However, as evident with comprehensive surveys, there is a noticeable decline in response rates as the number of questions escalates. Further complicating matters is the phenomenon known as the 'voter's paradox,' wherein the impact of a singular vote diminishes in larger elections. Both challenges can be addressed by sharding lengthy ballots among the entire voter base. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"In the PeaceFounder system, sharding is trivial due to votes being cast pseudonymously. The initial step in the sharding involves determining all feasible divisions of the ballot and methodically enumerating them. Subsequently, these shards are allocated to pseudonyms, achieved by systematically sorting and matching them in sequence.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Nevertheless, a pronounced security concern emerges. Suppose an adversary assumes control over the proposer and possesses knowledge of a select group of pseudonym owners and their inclinations. In that case, they can manipulate the election outcome by tailoring the proposal and shards. Specifically, critical questions can be allocated to a limited cohort, skewing results in their favour.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"To counteract this vulnerability, it's imperative for the proposer to commit to both the ballot and its associated shards, followed by a lottery to randomise the pseudonym list. Leveraging a DRAND service, which collaborates with multiple entities to execute threshold decryption, ensures the generation of predetermined, incorruptible random numbers [...]. These numbers subsequently serve as salt for hashing pseudonyms, which are sorted and allocated to shards accordingly. A critical aspect of this method is making sure the proposal is committed before the lottery result is announced to prevent adversaries from taking advantage of waiting for a favourable lottery outcome. This necessitates the involvement of auditors/monitors to timestamp the braidchain ledger commitments externally.","category":"page"},{"location":"#PeaceFounder.jl","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"","category":"section"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"(Image: ) (Image: )","category":"page"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"PeaceFounder is a centralised E2E verifiable e-voting system that leverages pseudonym braiding and history trees. The immutability of the bulletin board is maintained replication-free by voter’s client devices with locally stored consistency-proof chains. Meanwhile, pseudonym braiding done via an exponentiation mix before the vote allows anonymisation to be transactional with a single braider at a time. In contrast to existing E2E verifiable e-voting systems, it is much easier to deploy as the system is fully centralised, free from threshold decryption ceremonies, trusted setup phases and bulletin board replication. Furthermore, the body of a vote is signed with a braided pseudonym, enabling unlimited ballot types.","category":"page"},{"location":"#Introduction","page":"PeaceFounder.jl","title":"Introduction","text":"","category":"section"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"everal end-to-end (E2E) verifiable e-voting systems exist, such as Helios, Scytl, Belenios, ElectionGuard, Estonia's system, and Verificatum, with many available under open-source licences. They all encrypt and mix votes through a re-encryption shuffle and use a threshold decryption ceremony. This allows voters to track their encrypted votes and the public to verify the final tally. However, it depends on the integrity of the bulletin board and the coordination of the threshold decryption ceremony, presenting challenges for smaller communities and organisations.","category":"page"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"To make a point, let's consider a Helios voting system. The vote in Helios is stored in a group element, encrypted and signed by a digital signature provider, and then submitted to the bulletin board. When the vote closes, votes go through the reencryption shuffle and are decrypted in the threshold decryption ceremony. Voters can ensure that their vote has been counted by finding their encrypted vote within the list of inputs of the mix cascade. Furthermore, everyone can verify the final tally by counting the decrypted votes and verifying supplemented zero-knowledge proofs without compromising privacy. In this way, the integrity of the election result can be assured.","category":"page"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"However, issues like forced abstention and potential vote substitution of unverified votes can happen if authorities are corrupt and auditing/monitoring does not occur. Publishing vote-casting signatures can alleviate many of those issues, but that violates participation privacy. The threshold decryption ceremony further compounds the system's complexity; if more than a few are corrupt, votes can remain encrypted, while a low threshold risks privacy breaches. These factors, coupled with the technical intricacies of deployment, make Helios less feasible for small to medium-sized communities, leading to a preference for simpler black box systems to prevent questions from being asked, which can foster trust at the expense of trustworthiness.","category":"page"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"A significant improvement over Helios is the Selene system, which offers a voter-assigned tracking number and shows their votes next to them after the vote. Recent usability studies with Selene have demonstrated that voters appreciate the ability to verify their vote in plaintext. This allows them to discard their trust in advanced cryptography as they can see how their vote is counted. As the tracking number is not published before the vote and is deniable, it is also coercion-resistant. In addition to clever cryptography, it can also detect malware interference. However, the threshold decryption ceremony still needs to be deployed along with the bulletin board and thus would generally suit only state-like elections.","category":"page"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"Haenni & Spycher proposed a system using exponentiation mixes to anonymise voters' pseudonyms, eliminating the need for a threshold decryption ceremony. However, the benefits of such a system have yet to be reaped as it requires a trusted bulletin board that does not discard unfavourable votes; thus, deployment of such a system needs to be distributed and hence offers minor deployment improvements over Helios. Furthermore, over 13 years, a single open-source system has yet to be implemented.","category":"page"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"The innovative approach by PeaceFounder combines pseudonym braiding developed by Haenni & Spycher with a history trees-enabled bulletin board (Crosby & Wallach). When voters cast their vote, their devices receive inclusion proof of the vote, which can later be verified to be binding to the tally with consistency proof. By having only a few voters who request their device to check the proofs, the immutability of the bulletin board is guaranteed. Thus, once the server has assured that the vote is recorded, there is no way for it to be removed. This allows the system to be fully centralised and, thus, makes it easy to self-host.","category":"page"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"However, such a system poses many challenges compared to the orthodox approach. To protect against a corrupt server that discards unfavourable votes, voters must have the option to route the vote through proxy/monitor, which adds a challenge with coercion/bribery. To reap the benefits of braiding pseudonyms with any other community/organisation worldwide, the voters must be registered long before the vote starts, which would produce a bad user experience. Therefore, disengaging anonymisation from voting requires long-standing accounts, which poses an issue for continuous member registration and termination; on top of that, the votes need to be delivered over an anonymous channel not to be traceable by a corrupt authority. All of them are addressed with the PeaceFounder project in innovative ways.","category":"page"},{"location":"#Demo","page":"PeaceFounder.jl","title":"Demo","text":"","category":"section"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"An 8-minute YouTube demonstration is available here:","category":"page"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"(Image: IMAGE ALT TEXT HERE)","category":"page"},{"location":"#References","page":"PeaceFounder.jl","title":"References","text":"","category":"section"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"Rolf Haenni and Oliver Spycher. Secure internet voting on limited devices with anonymized DSA public keys. 2011\nScott A. Crosby and Dan S. Wallach. Efficient data structures for tamper-evident logging. 2009\nBjörn Terelius and Douglas Wikström. Proofs of restricted shuffles. 2010.","category":"page"}] +[{"location":"audittools/#PeaceFounder.AuditTools","page":"PeaceFounder.Core.AuditTools","title":"PeaceFounder.AuditTools","text":"","category":"section"},{"location":"audittools/","page":"PeaceFounder.Core.AuditTools","title":"PeaceFounder.Core.AuditTools","text":"Note: follow the feature proposal https://github.com/PeaceFounder/PeaceFounder.jl/issues/19","category":"page"},{"location":"audittools/","page":"PeaceFounder.Core.AuditTools","title":"PeaceFounder.Core.AuditTools","text":"PeaceFounder.Core.AuditTools","category":"page"},{"location":"audittools/","page":"PeaceFounder.Core.AuditTools","title":"PeaceFounder.Core.AuditTools","text":"Modules = [PeaceFounder.Core.AuditTools]\nOrder = [:module, :type, :function]","category":"page"},{"location":"audittools/#PeaceFounder.Core.AuditTools","page":"PeaceFounder.Core.AuditTools","title":"PeaceFounder.Core.AuditTools","text":"After ellections have ended the collector publishes a tally. To assert that votes have been accuratelly counted and that only legitimate voters have participated an audit takes place.\n\nEvery voter after ellections receives a final tally together with a consistency proof which proves that their vote is included in the ledger which have produced the tally. From the voter client voter reads four important parameters for the ballotbox:\n\ndeme_uuid: an UUID of the deme where the proposal is registered;\nproposal_index: a index at which the proposal is recorded in the braidchain ledger;\nledger_length: a number of collected votes in the ledger;\nledger_root: a ballotbox ledger root checksum.\n\nThe auditor also knows a hasher deme uses to make checksums which is immutable at the moment deme is created.\n\nLet's consider abstract functions to retrieve ballotbox and braidchain ledger archives from the internet with get_ballotbox_archive and get_braidchain_archive then the auditing can be done with a following script:\n\nbraidchain_archive = get_ballotbox_archive(uuid)\nballotbox_archive = get_ballotbox_archive(uuid, proposal_index)[1:ledger_length]\n\n@test checksum(ballotbox_archive, hasher) == ledger_root\n@test isbinding(braidchain_archive, ballotbox_archive, hasher)\n\nspec = crypto(braidchain_archive)\n\n@test audit(ballotbox_archive, spec)\n@test audit(braidchain_archive)\n\n@show tally(ballotbox_archive)\n\nNote that spec is read from the DemeSpec record in the braidchain which can be trusted as the tree braidchain ledger checksum is listed within a proposal's anchor. The proposal is the first record in history tree for the ballotbox thus it is bound to ledger_root checksum and so demespec record is also tied to ledger_root.\n\nFor convinience an audit method is provided which audits both archives at the same time:\n\naudit(ledger::BraidChainLedger)\naudit(ledger::BallotBoxLedger)\n\nisbinding(bbox::BallotBoxLedger, commit::Commit{BallotBoxState})\nisbinding(ledger::BraidChainLedger, commit::Commit{ChainState})\n\nisbinding(chain::BraidChainLedger, bbox::BraidChainLedger)\n\naudit(chain::BraidChainLedger, bbox::BallotBoxLedger, commit::Commit{BallotBoxState})\naudit(chain::BraidChainLedger, bbox::BallotBoxLedger, root::Digest, N::Int = length(bbox))\n\nNote that this audit does not check honesty of the registrar that it have admitted fake users to gain more influence in the ellection result. Properties being verified by the audit:\n\nLegitimacy: only and all eligiable voters cast their votes;\nFairness: every eligiable voter can vote at most once;\nImmutability: no vote can be deleted or modified when recorded in the ledger; \nTallied as Cast: all cast votes are counted honestly to predetermined procedure; \nSoftware independence: the previously audited properties for the evidence does not \n\ndepend on a trust in honest execution of peacefounder service nor honesty of the braiders who provides new pseudonyms for the deme members. In other words the previously listed properties would not be altered if adversary would have a full control over the peacefounder service and the braiders. \n\nThe immutability is ensured from voter's clients updating their consistency proof chain which includes their vote. If the vote gets removed from a chain every single voter who had cast their vote would get a proof for inconsistent ledger state called blame. The blame can be made public by the voter without revealing it's vote and thus ensures immutability and also persitance after votes are published. The auditable part here are the votes themselves signed with pseudonym which contract voter's clients to follow up at latter periods with consistency proofs. On top of that, other monitors can synchronize the ballotbox ledger and add assurances that way.\n\n\n\n\n\n","category":"module"},{"location":"schedulers/#PeaceFounder.Schedulers","page":"PeaceFounder.Schedulers","title":"PeaceFounder.Schedulers","text":"","category":"section"},{"location":"schedulers/","page":"PeaceFounder.Schedulers","title":"PeaceFounder.Schedulers","text":"Modules = [PeaceFounder.Schedulers]\nOrder = [:type, :function]","category":"page"},{"location":"schedulers/#PeaceFounder.Schedulers.Scheduler","page":"PeaceFounder.Schedulers","title":"PeaceFounder.Schedulers.Scheduler","text":"mutable struct Scheduler\n condition::Condition\n pool_interval::Union{Int, Nothing}\n retry_interval::Union{Int, Nothing}\n delay::Int\n started::Bool\n finished::Bool\n schedule::Vector{Tuple{DateTime, <:Any}}\nend\n\nRepresents a waitable object which resumes at predetermined scheduled times. A typical use for it is in the event loop like:\n\nscheduler = Scheduler(; retry_interval = 1)\n\nlock(scheduler) do \n schedule!(scheduler, now() + Second(1), value)\nend\n\nwhile true\n value = wait(scheduler)\n try\n # Do some stuff\n catch\n retry!(scheduler)\n end\nend\n\nIn the event loop one manages a state machine which can succed and fail. If it succeds a scheduled time is taken out from the scheduler and proceeds waiting the next event. In the case event at scheduled time had failed the scheduler is notified with retry! method and attempts to run the event loop againafter retry_interval until succeeds. \n\n\n\n\n\n","category":"type"},{"location":"schedulers/#Base.lock-Tuple{PeaceFounder.Schedulers.Scheduler}","page":"PeaceFounder.Schedulers","title":"Base.lock","text":"lock(scheduler::Scheduler)\n\nLock a scheduler. This is necessary to avoid simultanous modifications of the schedule field. Note that other Scheduler fields are not protected with the lock as thoose are considered internal. \n\n\n\n\n\n","category":"method"},{"location":"schedulers/#Base.notify-Tuple{PeaceFounder.Schedulers.Scheduler}","page":"PeaceFounder.Schedulers","title":"Base.notify","text":"notify(scheduler::Scheduler[, value])\n\nNotify a scheduler with a value which is returned at wait.\n\n\n\n\n\n","category":"method"},{"location":"schedulers/#Base.wait-Tuple{PeaceFounder.Schedulers.Scheduler}","page":"PeaceFounder.Schedulers","title":"Base.wait","text":"wait(scheduler::Scheduler)\n\nWait until next event is reached and return it's value. In the case event have run through smoothelly the scheduler event is droped with the next wait call. See also retry! method.\n\n\n\n\n\n","category":"method"},{"location":"schedulers/#PeaceFounder.Schedulers.next_event-Tuple{PeaceFounder.Schedulers.Scheduler}","page":"PeaceFounder.Schedulers","title":"PeaceFounder.Schedulers.next_event","text":"next_event(scheduler::Scheduler)\n\nReturn the next event in seconds and coresponding event value. Return nothing if no events are scheduled.\n\n\n\n\n\n","category":"method"},{"location":"schedulers/#PeaceFounder.Schedulers.retry!-Tuple{PeaceFounder.Schedulers.Scheduler}","page":"PeaceFounder.Schedulers","title":"PeaceFounder.Schedulers.retry!","text":"retry!(scheduler::Scheduler)\n\nNotifies the scheduler that event have run unsucesfully which reschedules it after specified retry_time(See Scheduler). \n\n\n\n\n\n","category":"method"},{"location":"schedulers/#PeaceFounder.Schedulers.schedule!-Tuple{PeaceFounder.Schedulers.Scheduler, Dates.DateTime, Any}","page":"PeaceFounder.Schedulers","title":"PeaceFounder.Schedulers.schedule!","text":"schedule!(scheduler::Scheduler, timestamp::DateTime[, value])\n\nSchedule an event at timestamp with a provided value. To avoid messing up a schedule acquire a scheduler's lock before adding the event as:\n\nlock(scheduler) do\n schedule!(scheduler, now() + Second(1), value)\nend\n\n\n\n\n\n","category":"method"},{"location":"schedulers/#PeaceFounder.Schedulers.waituntil-Tuple{Dates.DateTime}","page":"PeaceFounder.Schedulers","title":"PeaceFounder.Schedulers.waituntil","text":"waituntil(time::DateTime)\n\nWaits until given time is reached. \n\n\n\n\n\n","category":"method"},{"location":"setup/#Setup","page":"Setup","title":"Setup","text":"","category":"section"},{"location":"setup/","page":"Setup","title":"Setup","text":"In the PeaceFounder, communities are referred to as demes. To start a deme, we first need to initialise the cryptographic specification and generate a key for the election authority, which we shall refer to as the guardian. The guardian can further delegate a recorder, recruiter, braider, proposer and collector in the roster recorded in DemeSpec record.","category":"page"},{"location":"setup/#System-Setup","page":"Setup","title":"System Setup","text":"","category":"section"},{"location":"setup/","page":"Setup","title":"Setup","text":"(Image: )","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"The first step to begin using the PeaceFounder e-voting system is to host it, which is a straightforward process on Linux servers. Begin by downloading the snap package with the command below, and remember to change the architecture to arm64 if necessary:","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"curl -LOJ https://github.com/PeaceFounder/PeaceFounderAdmin/releases/download/v0.0.1/peacefounder-server-0.0.1-x64.snap","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"Next, proceed to install the package:","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"snap install --devmode peacefounder-server-0.0.1-x64.snap","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"This installation process automatically handles the compilation and configures the system to start automatically with systemd.","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"The admin panel, accessible at http://127.0.0.1:3221, is hosted locally and is not directly accessible from external networks. To access the admin panel remotely, use SSH to forward the local host port:","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"ssh -L 2332:127.0.0.1:3221 user@192.168.1.16","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"This trick does a secure authentification to the server and is free from PKI network trust assumptions.","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"The admin panel start with a setup wizard, guiding you to select a cryptographic group, choose a hash function, and generate keys. The server generates the guardian key, which is then encrypted with the provided password and stored in the deme record (a feature currently not implemented). Alternatively, you can use the advanced configurator. This option allows for local creation and signing of the deme record, with the option to encrypt the guardian key on the record (also yet to be implemented). The configurator also facilitates server migration, allowing you to input an existing tarball of braidchain records. The deme record is then appended as the last record, enabling continuity (this feature is also pending implementation).","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"Once the wizard is complete, the PeaceFounder server becomes active at http://0.0.0.0:4585. This is the public access point for clients and exposes the REST API. Further configurations, such as setting up an SMTP server to send invitations to prospective members, are done in the Settings panel. Here, you also need to specify an address through which clients can connect to the server. This could be a local address, a public IP, or a DNS pointing to the PeaceFounder REST API.","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"It's important to note that configuring the system doesn't require a TLS certificate for security, as all replies are signed with braidchain and ballotbox tree root commits. Using TLS can be detrimental as it might lower the threshold for making the system vulnerable to DDOS attacks since TLS session resumption has to be disabled to maintain voter anonymity. Each session would require a new key exchange, relying on a relatively costly group operation. Nevertheless, adding TLS currently wouldn't incur additional costs, as HTTP request processing performance is currently not optimised. Furthermore, the PeaceFounder client functions smoothly, even when the server is configured behind NGINX.","category":"page"},{"location":"setup/#Member-Registration","page":"Setup","title":"Member Registration","text":"","category":"section"},{"location":"setup/","page":"Setup","title":"Setup","text":"(Image: )","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"The process of member registration is conducted via email, through which a unique token is dispatched to the user. Unlike JWT tokens, which are typically incorporated into the header of a TLS connection, the token in this system serves a different purpose. It is utilised as a key in the format HMAC(body|timestamp, token) to authenticate requests. To enable the server to identify the origin of the request, a tokenid=Hash(token) is included in the header (currently, ticketid is used but will be made obsolete shortly).","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"When an invite is entered into the PeaceFounder client, the following steps are performed : ","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"The device will retrieve deme specification parameters from the provided address, which will be compared with the hash in the invite;\nThe cryptographic parameters are initialised, and a new key pair is generated;\nThe public key will be authenticated with HMAC using the invite token and will be sent to the deme server, which shall return the public key signed by the registrar, which we shall refer to as the admission certificate;\nIn the last step, the device retrieves the current braidchain generator and computes its pseudonym. This, together with the admission certificate, is signed by the member's private key, which consists of a member certificate. The member certificate is sent to the braidchain until History Tree inclusion proof is received, concluding the process. If the generator has changed, a new pseudonym is recomputed.","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"To guarantee the auditability of the electoral roll, the process involves members signing the received invitations and their corresponding membership certificate record index with a widely trusted digital identity and returning the document to the guardian. This method is robust and effective; the invitation includes a demespec, ensuring that the client has securely interacted with the claimed entity and has used correct cryptographic parameters. Additionally, the member index acts as a confirmation of successful registration. Such a mechanism renders this e-voting system universally adaptable, making it a viable option globally in regions where any form of digital identity infrastructure is in place.","category":"page"},{"location":"setup/#Voting","page":"Setup","title":"Voting","text":"","category":"section"},{"location":"setup/","page":"Setup","title":"Setup","text":"(Image: )","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"The registration of members is followed by the generation of a braid. To boost anonymity, several braids can chained together in sequence. This technique raises the anonymity threshold - the least number of entities required to be breached to associate a member's certificate with their voting pseudonym. Currently, the system supports only self-braiding, setting the maximum anonymity threshold at one. Future updates aim to enable braiding between different demes, which could be either fictional entities created for specific votes or real communities worldwide. The integrity of the final braid receipt is verified using Zero-Knowledge Proofs (ZKPs) and recorded in the braidchain.","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"To initiate voting, the guardian sets up a new proposal. This proposal includes key details such as opening and closing times, title, description, ballot, and an anchor. The anchor is essentially the index of a braid, whose generator and pseudonyms are utilised for the vote. Members registered after the braid’s creation are not included in that particular vote. However, continuous member registration and the ability to self-braid should minimise such exclusions. The anchor also facilitates linking multiple proposals, allowing fluid voting situations where members can alter their votes at predetermined times during a representative’s term.","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"As voting progresses, each vote is logged in the ballot box ledger, displaying the vote cast index, timestamp, sequence number, and vote status. Voters receive a receipt including the timestamp and cast index as a tracking number, which enables them to locate their vote on the bulletin board. The pseudonym links all votes cast from a single device. Plans are underway to introduce an additional token for verifying the vote’s authenticity and a public bulletin board hosted as a static webpage. This will allow voters to ensure their vote is cast as intended and counted accurately.","category":"page"},{"location":"setup/#BraidChain-Ledger","page":"Setup","title":"BraidChain Ledger","text":"","category":"section"},{"location":"setup/","page":"Setup","title":"Setup","text":"(Image: )","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"The BraidChain and BallotBox ledgers together create publicly available proof of election integrity. The BallotBox ledger is straightforward, containing votes signed with the voter's pseudonym without altering the state of the ballot box. In contrast, the BraidChain ledger is more complex, and every record changes the system state. Auditors can run audit commands on records stored in the disk (in development) that require no deep understanding of the underlying data structure. However, in cases where issues arise, having a reference point to communicate about these issues effectively is beneficial.","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"Each record in the BraidChain ledger is authenticated by an issuer's digital signature. To be included, the issuer's record must possess the necessary authorisation, with corresponding public keys detailed in the DemeSpec record, particularly in the roster section. Should there be a need to change a party's key, a revised DemeSpec record is issued, authenticated with the Guardian's private key. It's crucial to secure this key diligently to prevent adversaries from assuming authority and hijacking the election process, which could disrupt availability and create an inconsistent state for participants, leading to the generation of blame proofs. In events where the Guardian's key is compromised, it would necessitate the re-establishment of the deme from scratch. Looking ahead, a potential improvement could involve requiring multiple parties to sign off on the DemeSpec record for it to be valid, thus reducing the likelihood of such breaches.","category":"page"},{"location":"setup/#Developer-Documentation","page":"Setup","title":"Developer Documentation","text":"","category":"section"},{"location":"setup/","page":"Setup","title":"Setup","text":"In this example, the cryptographic parameters are specified in the crypto variable and are further used to initialise the keys on the server for a recruiter, braider, collector and recorder with Mapper.initialize!(crypto) call. The identities are retrieved with Mapper.system_roles() call and are used to fill fields in the DemeSpec record. Afterwards, it is signed by the guardian and is submitted to the server with Mapper.capture!(demespec), which finalises the server configuration, after which the server can be started.","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"import PeaceFounder: Model, Mapper, Service, id, approve\nimport PeaceFounder.Model: TicketID, CryptoSpec, DemeSpec, Signer\nimport HTTP\n\ncrypto = CryptoSpec(\"sha256\", \"EC: P_192\")\n\nGUARDIAN = Model.generate(Signer, crypto)\nPROPOSER = Model.generate(Signer, crypto)\n\nMapper.initialize!(crypto)\nroles = Mapper.system_roles()\n\ndemespec = DemeSpec(; \n uuid = Base.UUID(121432),\n title = \"A local democratic community\",\n crypto = crypto,\n guardian = id(GUARDIAN),\n recorder = roles.recorder,\n recruiter = roles.recruiter,\n braider = roles.braider,\n proposer = id(PROPOSER),\n collector = roles.collector\n) |> approve(GUARDIAN) \n\nMapper.capture!(demespec)\n\nHTTP.serve(Service.ROUTER, \"0.0.0.0\", 80)","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"The second part is to set up the entry for registration within the deme. It is up to the guardian to decide how new members are added to the deme and how their identity is being tracked and made transparent so that members are assured that someone has created fake identities to vote multiple times.","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"
\n \n
Sequence diagram illustrating client registration with a deme. The process begins when the client requests an invitation from the registrar and concludes when a certified pseudonym is submitted to the Braidchain ledger. The protocol serves multiple goals: 1) It simplifies integration by requiring only a hash function for authorization of new member requests. 2) It prevents inconsistencies between the client's device and the braidchain by allowing repetition of the final step. 3) It ensures that registration can continue even when the chain is temporarily locked for new members, by allowing catch-up with the current relative generator. Future updates aim to combine the last two steps to reduce the number of communication rounds required.
\n
","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"That would best be done within the organisation's website, where members can log in and get an invite as a string or QR code scanned in the PeaceFounder client application. To facilitate that, the PeaceFounder service offers a recruiter endpoint from which invites can be obtained and accessed, knowing ROUTE = \"0.0.0.0:80\" and recruiter symmetric key KEY = Mapper.get_recruit_key(). That makes it relatively easy to integrate into the webpage as it only needs the ability to read some JSON and sha256 hash functions used to authenticate and compute registration tokens at the endpoints. That also makes it redundant to add a TLS certificate for the PeaceFoudner service. ","category":"page"},{"location":"setup/#Registrar-setup","page":"Setup","title":"Registrar setup","text":"","category":"section"},{"location":"setup/","page":"Setup","title":"Setup","text":"**Note: This setup part has been deprecated in favour of PeaceFounderAdmin. **","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"
\n \n
A registration form available from Recruiters.jl. When a user puts in his name and email address, a unique invite is automatically sent to the user at the provided email address for registration with the deme.
\n
","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"To make it easier to start using the peacefounder, a simple registrar facade, as shown in the image above, is available in Recruiters.jl. When a user puts in his name and email address, a unique invite is automatically sent to the email with which the user can register. This can also serve as a starting point to make a custom registrar facade and see the involved components, which makes it work. To set it up, we first need to export variables for the deme:","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"export DEME_ROUTE='http://0.0.0.0:80'\nexport DEME_HASHER='sha256'\nexport DEME_RECRUIT_KEY='THE_RECRUIT_KEY'","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"And also for the SMTP service with which recruit emails are going to be sent. This is specified in the following variables:","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"export RECRUIT_SMTP='smtps://mail.inbox.lv:465'\nexport RECRUIT_EMAIL='demerecruit@inbox.lv'\nexport RECRUIT_PASSWORD='THE_EMAIL_PASSWORD'","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"After these environment variables are set, the recruiter service can be started as:","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"using Recruiters\n\ntitle = \"Local Democratic Community\"\npitch = \"\"\"\n

Are you looking for a way to get involved in local politics and make a difference in your community? Do you want to connect with like-minded individuals who share your values and beliefs? If so, we invite you to join our Local Democratic Community.

\n\n

Our community is a group of individuals who are passionate about promoting progressive values and creating positive change in our neighborhoods and towns. We believe that by working together, we can build a more just and equitable society for everyone. As a member of our community, you will have the opportunity to attend events, participate in volunteer activities, and engage in meaningful discussions about the issues that matter most to you.

\n\"\"\"\n\nRecruiters.serve(title, pitch)","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"By default, the serve function reads in the environment variables, but if necessary, those can be specified manually by a set of keyword arguments. See docs for further use of those. ","category":"page"},{"location":"setup/#Braiding","page":"Setup","title":"Braiding","text":"","category":"section"},{"location":"setup/","page":"Setup","title":"Setup","text":"Braiding is a method in which the mix server shuffles input member public keys and raises that to the power of a secret exponent x, resulting in a new set of public keys with relative generator h = g^x. This procedure must be executed honestly, which can be verified with zero-knowledge proofs.","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"In particular, ElGamal re-encryption shuffle is done first on the elements (a b) leftarrow (1 Y_i) for which a zero knowledge of proof compatible with the Verificatum verifier is produced. Then, a proof of decryption for c_i leftarrow b_i^x and h leftarrow g^x is produced. That then is used to calculate the resulting member public keys as Y_i leftarrow ca.","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"In PeaceFounder, this operation can be executed with the following lines of code:","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"input_generator = Mapper.get_generator()\ninput_members = Mapper.get_members()\n\n# This line is executed on an independent mix\nbraidwork = Model.braid(input_generator, input_members, demespec, demespec, Mapper.BRAIDER[]) \nMapper.submit_chain_record!(braidwork)","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"The first demespec contains cryptographic parameters for the group specification for input_generator and input_members. The second demespec is added by the braider, which signs the resulting braid and assures that an independent entity endorsed by a different deme provides assurances to the voter that his vote remains private from the guardian.","category":"page"},{"location":"setup/#Proposal-announcement","page":"Setup","title":"Proposal announcement","text":"","category":"section"},{"location":"setup/","page":"Setup","title":"Setup","text":"A proposal to the PeaceFounder service can be added with a PROPOSER key as follows:","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"commit = Mapper.get_chain_commit()\n\nproposal = Proposal(\n uuid = Base.UUID(23445325),\n summary = \"Should the city ban \\\n all personal automotive vehicle usage?\",\n description = \"\",\n ballot = Ballot([\"yes\", \"no\"]),\n open = Dates.now(),\n closed = Dates.now() + Dates.Second(2),\n collector = roles.collector,\n\nstate = state(commit)\n\n) |> approve(PROPOSER)\n\n\nack = Mapper.submit_chain_record!(proposal) ","category":"page"},{"location":"setup/","page":"Setup","title":"Setup","text":"Notice that state(commit) is added to the proposal. This anchors the relative generator on which the votes are cast.","category":"page"},{"location":"audit/#Audit","page":"Audit","title":"Audit","text":"","category":"section"},{"location":"audit/","page":"Audit","title":"Audit","text":"Note: The demonstrated audit API is in progress and is discussed further in a feature proposal Evidence Auditing with Terminal API. Currently, the best auditing strategy is to recreate the braid chain and ballot box ledger from one record at a time.","category":"page"},{"location":"audit/","page":"Audit","title":"Audit","text":"After elections have ended, the collector publishes a tally. After elections, every voter receives a final tally together with consistency proof, which proves that their vote is included in the ledger that has produced the tally. From the voter client, the voter reads four important parameters for the ballotbox:","category":"page"},{"location":"audit/","page":"Audit","title":"Audit","text":"deme_uuid: a UUID of the deme where the proposal is registered;\nproposal_index: an index at which the proposal is recorded in the braidchain ledger;\nledger_length: a number of collected votes in the ledger;\nledger_root: a ballotbox ledger root checksum.","category":"page"},{"location":"audit/","page":"Audit","title":"Audit","text":"The auditor also knows a hasher deme used to make checksums, which is immutable when the deme is created.","category":"page"},{"location":"audit/","page":"Audit","title":"Audit","text":"To assert the integrity of the vote, an audit takes place. Let's consider abstract functions to retrieve ballotbox and braidchain ledger archives from the internet with get_ballotbox_archive and `getbraidchainarchive; then the auditing can be done with the following script:","category":"page"},{"location":"audit/","page":"Audit","title":"Audit","text":"braidchain_archive = get_ballotbox_archive(uuid)\nballotbox_archive = get_ballotbox_archive(uuid, proposal_index)[1:ledger_length]\n\n@test checksum(ballotbox_archive, hasher) == ledger_root\n@test isbinding(braidchain_archive, ballotbox_archive, hasher)\n\nspec = crypto(braidchain_archive)\n\n@test audit(ballotbox_archive, spec)\n@test audit(braidchain_archive)\n\n@show tally(ballotbox_archive)","category":"page"},{"location":"audit/","page":"Audit","title":"Audit","text":"Note that spec is read from the DemeSpec record in the braidchain, which can be trusted as the tree braidchain ledger checksum is listed within a proposal's anchor. The proposal is the first record in the history tree for the ballotbox; thus, it is bound to the ledger_root checksum, so the demespec record is also tied to ledger_root.","category":"page"},{"location":"audit/","page":"Audit","title":"Audit","text":"For convenience, an audit method is provided that audits both archives at the same time:","category":"page"},{"location":"audit/","page":"Audit","title":"Audit","text":"braidchain_archive = get_ballotbox_archive(uuid)\nballotbox_archive = get_ballotbox_archive(uuid, proposal_index)[1:ledger_length]\n\n@test checksum(ballotbox_archive, hasher) == ledger_root\n@test audit(braidchain_archive, ballotbox_archive, hasher)\n\n@show tally(ballotbox_archive)","category":"page"},{"location":"audit/","page":"Audit","title":"Audit","text":"Note that this audit does not check the honesty of the registrar and that it has not admitted fake users to gain more influence in the election result. Properties being verified by the audit:","category":"page"},{"location":"audit/","page":"Audit","title":"Audit","text":"Legitimacy: only eligible voters cast their votes;\nEquality: every eligible voter can vote at most once;\nImmutability: no vote can be deleted or modified after being recorded in the ledger; \nTallied as Cast: all cast votes are counted honestly according to predetermined procedure; ","category":"page"},{"location":"audit/","page":"Audit","title":"Audit","text":"All these properties together ensure software independence so that the resulting tally does not depend on trust in the honest execution of either peacefounder service or braiders. In other words, the previously listed properties would not be altered if the adversary had full control over the peacefounder service and the braiders. ","category":"page"},{"location":"audit/","page":"Audit","title":"Audit","text":"The immutability is ensured by voter's clients updating their consistency proof chain, which includes their vote. If the vote gets removed from a chain, every voter who cast their vote will get proof for an inconsistent ledger state called blame. The voter can make the blame public without revealing their vote, thus ensuring immutability and persistence after votes are published. The auditable part here is the votes signed with a pseudonym, which contract voters' clients to follow up at later periods with consistency proofs. On top of that, other monitors can synchronise the ballotbox ledger and add assurances that way.","category":"page"},{"location":"model/#PeaceFounder.Core.Model","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model","text":"","category":"section"},{"location":"model/#Primitives","page":"PeaceFounder.Core.Model","title":"Primitives","text":"","category":"section"},{"location":"model/","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model","text":"Modules = [PeaceFounder.Core.Model]\nOrder = [:type, :function]\nPages = [\"Core/Model/crypto.jl\", \"Core/Model/seal.jl\"]","category":"page"},{"location":"model/#PeaceFounder.Core.Model.Commit","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Commit","text":"Commit{T}\n state::T\n seal::Seal\nend\n\nRepresents a commited ledger state to which issuer can be held accountable for integrity. It is assumed that T implements index and root necessaary to fix a ledger state. \n\nInterface: id, issuer, verify, index, root, state\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.CryptoSpec","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.CryptoSpec","text":"struct CryptoSpec\n hasher::HashSpec\n group::GroupSpec\n generator::Generator\nend\n\nSpecification of cryptographic parameters which are used for public key cryptography, message hashing and authetification codes. \n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.Digest","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Digest","text":"struct Digest\n data::Vector{UInt8}\nend\n\nA message digest obtained applying a hash function on a message or a document. See method digest.\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.Generator","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Generator","text":"struct Generator\n data::Vector{UInt8}\nend\n\nDatatype which stores cryptogrpahic group point in standart octet form intended to be used as a base. See also Pseudonym.\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.HMAC","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.HMAC","text":"struct HMAC\n key::Vector{UInt8}\n hasher::HashSpec\nend\n\nRepresent a hash message authetification code authorizer.\n\nInterface: hasher, digest, key\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.Pseudonym","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Pseudonym","text":"struct Pseudonym\n pk::Vector{UInt8}\nend\n\nA datatype which stores public key in canonical standart octet form.\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.Seal","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Seal","text":"struct Seal\n pbkey::Pseudonym\n sig::Signature\nend\n\nA wrapper type for a signature which adds a public key of signature issuer. See seal method. \n\nInterface: pseudonym, verify\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.Signer","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Signer","text":"struct Signer\n spec::CryptoSpec\n pbkey::Pseudonym\n key::BigInt\nend\n\nA signer type. See a method generate(Signer, spec) for initialization.\n\nInterface: pseudonym, id, sign, seal, approve\n\n\n\n\n\n","category":"type"},{"location":"model/#HistoryTrees.root-Tuple{PeaceFounder.Core.Model.Commit}","page":"PeaceFounder.Core.Model","title":"HistoryTrees.root","text":"root(x)::Digest\n\nReturn a ledger root hash.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.digest-Tuple{Any, Any}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.digest","text":"digest(message::Vector{UInt8}, hasher::HashSpec)::Digest\ndigest(document, spec) = digest(canonicalize(message)::Vector{UInt8}, hasher(spec)::HashSpec)\n\nReturn a resulting digest applying hasher on the given message. When message is not octet string a canonicalize method is applied first.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.digest-Tuple{Vector{UInt8}, CryptoGroups.Specs.HashSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.digest","text":"digest(bytes::Vector{UInt8}, hasher::HashSpec)::Digest\ndigest(x, spec) = digest(canonicalize(x)::Vector{UInt8}, hasher(spec)::HashSpec)\n\nCompute a hash digest. When input is not in bytes the canonicalize method is applied first.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.generate-Tuple{Type{PeaceFounder.Core.Model.Signer}, PeaceFounder.Core.Model.CryptoSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.generate","text":"generate(Signer, spec::CryptoSpec)::Signer\n\nGenerate a unique private key and return a Signer object. \n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.generator-Tuple{PeaceFounder.Core.Model.CryptoSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.generator","text":"generator(crypto::CryptoSpec)::Generator\n\nReturn a generator of the specification. \n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.generator-Tuple{Union{CryptoGroups.Specs.ECP, CryptoGroups.Specs.EC2N, CryptoGroups.Specs.Koblitz}}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.generator","text":"generator(spec::Spec)::Generator\n\nReturn a generator of spec.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.hasher-Tuple{PeaceFounder.Core.Model.HMAC}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.hasher","text":"hasher(spec)::HashSpec\n\nAccess a hasher function from a given specification.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.index-Tuple{PeaceFounder.Core.Model.Commit}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.index","text":"index(x)::Int\n\nReturn an index of a ledger state.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.issuer-Tuple{PeaceFounder.Core.Model.Commit}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.issuer","text":"issuer(x)\n\nIn case an object x is cryptographically signed return an issuer of who have issued the signature. See also id.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.key-Tuple{PeaceFounder.Core.Model.HMAC}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.key","text":"key(x)\n\nAccess a secret key of an object x.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.seal-Tuple{Vector{UInt8}, PeaceFounder.Core.Model.Signer}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.seal","text":"seal(message::Vector{UInt8}[, generator::Generator], signer::Signer)::Seal\n\nSign a bytestring message with signer's private key and specification and return a signature as a Seal. When generator is provided it is used as a base for the signature. See also sign.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.sign-Tuple{PeaceFounder.Core.Model.Digest, PeaceFounder.Core.Model.Generator, PeaceFounder.Core.Model.Signer}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.sign","text":"sign(digest::Digest[, generator::Generator], signer::Signer)::Signature\n\nSign a digest as an integer with signer's private key and specification. This method avoids running hashing twice when that is done externally. When generator is provided it is used as a base for the signature.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.sign-Tuple{Vector{UInt8}, PeaceFounder.Core.Model.Generator, PeaceFounder.Core.Model.Signer}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.sign","text":"sign(message::Vector{UInt8}[, generator::Generator], signer::Signer)::Signature\n\nSign a bytestring message with signer's private key and specification. When generator is provided it is used as a base for the signature.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.state-Tuple{PeaceFounder.Core.Model.Commit}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.state","text":"state(commit::Commit{T})::T\n\nReturn a ledger state. T implements index and root. \n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.canonicalize","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.canonicalize","text":"ToDo: a well specified encoding is essential here. Binary tree encoding may suffice here. More fancy approach would be to use a DER encoding. Meanwhile JSON shall be used.\n\n\n\n\n\n","category":"function"},{"location":"model/","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model","text":"PeaceFounder.Core.Model.pseudonym","category":"page"},{"location":"model/#PeaceFounder.Core.Model.pseudonym","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.pseudonym","text":"pseudonym(signer::Signer, [generator])::Pseudonym\n\nReturn a pseudonym of a signer at a given relative generator. If generator is not passed returns identity pseudonym. (See also id)\n\n\n\npseudonym(seal::Seal)::Pseudonym\n\nReturn a pseudonym of a seal. Note that it is not equal to identity when the signature is issued on a relative generator.\n\n\n\npseudonym(vote::Vote)::Pseudonym\n\nReturn a pseudonym used to seal the vote.\n\n\n\n\n\n","category":"function"},{"location":"model/","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model","text":"PeaceFounder.Core.Model.id","category":"page"},{"location":"model/#PeaceFounder.Core.Model.id","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.id","text":"id(document)::Pseudonym\n\nReturn identity pseudonym of a document issuer.\n\n\n\nid(signer)::Pseudonym\n\nReturn identity pseudonym of a signer.\n\n\n\n\n\n","category":"function"},{"location":"model/","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model","text":"PeaceFounder.Core.Model.verify","category":"page"},{"location":"model/#PeaceFounder.Core.Model.verify","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.verify","text":"verify(message, seal::Seal, [generator::Generator], crypto::CryptoSpec)::Bool\nverify(message, pk::Pseudonym, sig::Signature, [generator::Generator], crypto::CryptoSpec)::Bool\n\nVerify the cryptographic signature of the message returning true if valid. An optional generator can be given when signature is issued on a relative generator differing from a base specification crypto. \n\n\n\nverify(document[, generator::Generator], crypto::CryptoSpec)::Bool\n\nVerify a cryptographic signature of the document returning true if valid. \n\n\n\nverify(braidwork::BraidReceipt, crypto::CryptoSpec)::Bool\n\nVerify a braider issued cryptographic signature for the braidwork and a zero knowledge proofs. Returns true if both checks succeed.\n\n\n\n\n\n","category":"function"},{"location":"model/#BraidChain","page":"PeaceFounder.Core.Model","title":"BraidChain","text":"","category":"section"},{"location":"model/","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model","text":"Modules = [PeaceFounder.Core.Model]\nOrder = [:type, :function]\nPages = [\"Core/Model/braidchain.jl\", \"Core/Model/braids.jl\"]","category":"page"},{"location":"model/#PeaceFounder.Core.Model.Admission","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Admission","text":"struct Admission\n ticketid::TicketID\n id::Pseudonym\n timestamp::DateTime\n approval::Union{Seal, Nothing}\nend\n\nRepresents an admission certificate for a pseudonym id. \n\nInterface: approve, issuer, id, ticket, [isadmitted]\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.ChainState","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.ChainState","text":"struct ChainState\n index::Int\n root::Digest\n generator::Generator\n member_count::Int\nend\n\nRepresents a chain state metadata which is sufficient for integrity checks.\n\nInterface: index, root, generator\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.DemeSpec","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.DemeSpec","text":"struct DemeSpec <: Transaction\n uuid::UUID\n title::String\n crypto::CryptoSpec\n guardian::Pseudonym\n recorder::Pseudonym\n registrar::Pseudonym\n braider::Pseudonym\n proposer::Pseudonym \n collector::Pseudonym\n timestamp::Union{DateTime, Nothing} = nothing\n signature::Union{Signature, Nothing} = nothing\nend\n\nRepresents a deme configuration parameters issued by the guardian.\n\nuuid::UUID an unique random generated community identifier;\ntitle::String a community name with which deme is represented;\ncrypto::CryptoSpec cryptographic parameters for the deme;\nguardian::Pseudonym an issuer for this demespec file. Has authorithy to set a roster:\nrecorder::Pseudonym an authorithy which has rights to add new transactions and is responsable for braidchain's ledger integrity. Issues Commit{ChainState};\nregistrar::Pseudonym an authorithy which has rights to authorize new admissions to the deme. See Admission and Membership;\nbraider::Pseudonym an authorithy which can do a legitimate braid jobs for other demes. See BraidReceipt; \nproposer::Pseudonym an authorithy which has rights to issue a proposals for the braidchain. See Proposal;\ncollector::Pseudonym an authorithy which is repsonsable for collecting votes for proposals. This is also recorded in the proposal itself.\ntimestamp::Union{DateTime, Nothing} time when signature is being issued;\nsignature::Union{Signature, Nothing} a guardian issued signature. \n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.Membership","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Membership","text":"struct Membership <: Transaction\n admission::Admission\n generator::Generator\n pseudonym::Pseudonym\n approval::Union{Signature, Nothing} \nend\n\nA new member certificate which rolls in (anouances) it's pseudonym at current generator signed with identity pseudonym certified with admission certificate issued by registrar. This two step process is necessary as a checkpoint in situations when braidchain ledger get's locked during a new member resgistration procedure.\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.TicketID","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.TicketID","text":"struct TicketID\n id::Vector{UInt8}\nend\n\nRepresents a unique identifier for which a recruit tooken is issued. In case of necessity id can contain a full document, for instance, registration form, proof of identity and etc. In case a privacy is an issue the id can contain a unique identifier which can be matched to an identity in an external database.\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.Transaction","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Transaction","text":"Transaction\n\nRepresents an abstract record type which can be stored in the braidchain ledger. \n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.approve-Tuple{PeaceFounder.Core.Model.Admission, PeaceFounder.Core.Model.Signer}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.approve","text":"approve(x::T, signer::Signer)::T\n\nCryptographically sign a document x::T and returns a signed document with the same type. To check whether a document is signed see issuer method.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.approve-Tuple{PeaceFounder.Core.Model.Membership, PeaceFounder.Core.Model.Signer}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.approve","text":"approve(member::Membership, signer::Signer)::Membership\n\nSign a member certificate and return it with approval field filled.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.generator-Tuple{PeaceFounder.Core.Model.Membership}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.generator","text":"generator(member::Membership)::Generator\n\nGenerator at which member tries to roll in the braidchain.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.id-Tuple{PeaceFounder.Core.Model.Membership}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.id","text":"id(member::Membership)::Pseudonym\n\nIdentity pseudonym for a member. \n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.isbinding-Tuple{PeaceFounder.Core.Model.Admission, PeaceFounder.Core.Model.DemeSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.isbinding","text":"isbinding(admission::Admission, spec::DemeSpec)\n\nCheck whether issuer of admission is a registrar set in spec.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.issuer-Tuple{PeaceFounder.Core.Model.Membership}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.issuer","text":"issuer(member::Membership)::Pseudonym\n\nThe identiy of registrar who signed admission.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.members-Tuple{PeaceFounder.Core.Model.BraidChainLedger, Int64}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.members","text":"members(ledger::BraidChainLedger[, index::Int])::Set{Pseudonym}\n\nReturn a set of member pseudonyms at relative generator at braidchain ledger row index. If index is omitted return a current state value.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.pseudonym-Tuple{PeaceFounder.Core.Model.Membership}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.pseudonym","text":"pseudonym(member::Membership)::Pseudonym\n\nPseudonym for a member at the generator(member). \n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.ticket-Tuple{PeaceFounder.Core.Model.Admission}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.ticket","text":"ticket(x::Admission)\n\nReturn a TicketID which is admitted.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.ticket-Tuple{PeaceFounder.Core.Model.Membership}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.ticket","text":"ticket(member::Membership)\n\nTicket for a member admission certificate.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.BraidReceipt","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.BraidReceipt","text":"struct BraidReceipt <: Transaction\n braid::Simulator\n producer::DemeSpec\n approval::Union{Seal, Nothing}\nend\n\nRepresents a braider's computation which is supported with zero knowledge proof of shuffle and decryption assuring it's corectness stored in a braid field; producer denotes a deme where the braid is made. To assert latter the the braider signs the braidwork and stores that in the aproval field. See a braid method.\n\nInterface: approve, verify, input_generator, input_members, output_generator, output_members\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.approve-Tuple{PeaceFounder.Core.Model.BraidReceipt, PeaceFounder.Core.Model.DemeSpec, PeaceFounder.Core.Model.Signer}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.approve","text":"approve(braid::BraidReceipt, spec::DemeSpec, braider::Signer)\n\nSign a braidwork with a braider. Throws an error if braider is not in the producer demespec.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.braid-Tuple{PeaceFounder.Core.Model.Generator, Union{Set{PeaceFounder.Core.Model.Pseudonym}, Vector{PeaceFounder.Core.Model.Pseudonym}}, PeaceFounder.Core.Model.CryptoSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.braid","text":"braid(generator::Generator, members::Union{Vector{Pseudonym}, Set{Pseudonym}}, consumer::DemeSpec, producer::DemeSpec; verifier = (g) -> ProtocolSpec(; g))\n\nSelects a private exponent x at random and computes a new generator g = g^x and member_i=member_i^x returns the latter in a sorted order and provides a zero knowledge proof that all operations have been performed honestly. In partucular, not including/droping new member pseudonyms in the process. consumer attributes are necessary to interepret generator and pseudonym group elements with which the computation is performed. \n\nBy default a Verificatum compatable verifier is used for performing reencryption proof of shuffle\n\nA verifier can be configured with a keyword argument. By default a Verificatum compatable verifier for a proof of shuffle is used.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.input_generator-Tuple{PeaceFounder.Core.Model.BraidReceipt}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.input_generator","text":"input_generator(braid::BraidReceipt)\n\nReturn input generator of the braid.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.input_members-Tuple{PeaceFounder.Core.Model.BraidReceipt}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.input_members","text":"input_members(braid::BraidReceipt)\n\nReturn input member pseudonyms of the braid at provided input generator. See input_generator\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.output_generator-Tuple{PeaceFounder.Core.Model.BraidReceipt}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.output_generator","text":"output_generator(braid::BraidReceipt)\n\nReturn output genertor of the braid.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.output_members-Tuple{PeaceFounder.Core.Model.BraidReceipt}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.output_members","text":"output_members(braid::BraidReceipt)\n\nReturn output member pseudonyms of the braid at a resulting output generator. See output_generator\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.verify-Tuple{PeaceFounder.Core.Model.BraidReceipt, PeaceFounder.Core.Model.CryptoSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.verify","text":"verify(braid::BraidReceipt, crypto::CryptoSpec)\n\nVerifies a braid approval and then it's zero knowledge proofs. A crypto argument is provided to avoid downgrading attacks. \n\n\n\n\n\n","category":"method"},{"location":"model/#Ballot-Box","page":"PeaceFounder.Core.Model","title":"Ballot Box","text":"","category":"section"},{"location":"model/","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model","text":"Modules = [PeaceFounder.Core.Model]\nOrder = [:type, :function]\nPages = [\"Core/Model/ballotbox.jl\"]","category":"page"},{"location":"model/#PeaceFounder.Core.Model.Ballot","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Ballot","text":"struct Ballot\n options::Vector{String}\nend\n\nRepresents a simple ballot form for multiple choice question. \n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.BallotBoxState","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.BallotBoxState","text":"struct BallotBoxState\n proposal::Digest\n seed::Digest\n index::Int\n root::Digest\n tally::Union{Nothing, Tally} \n view::Union{Nothing, BitVector} # \nend\n\nRepresents a public ballot box state. Contains an immutable proposal and seed digest; a current ledger index, history tree root. When ellections end a tally is included in the state and a view is added listing all counted votes. Note that the view attribute is important for a client to know whether it's key have leaked and somone lese havbe superseeded it's vote by revoting.\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.CastReceipt","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.CastReceipt","text":"struct CastReceipt\n vote::Digest\n timestamp::DateTime\nend\n\nRepresents a ballotbox ledger receipt which is hashed for a history tree. It's sole purpose is to assure voters that their vote is included in the ledger while also adding additional metadata as timestamp and. In contrast to CastRecord it does not reveal how voter have voted thus can be published during ellections without violating fairness property. For some situations it may be useful to extend the time until the votes are published as that can disincentivice coercers and bribers as they would not know whether their coerced vote have been superseeded in revoting. See receipt method for it's construction from a CastRecord.\n\nNote that a blind signature could be commited as H(signature|H(vote)) to avoid tagging the use of pseudonym during ellections while collector could issue only a one blind signature for a voter. Note that members whoose private key could have been stolen could not obtain a valid signature for participation and that could be a good thing!\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.CastRecord","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.CastRecord","text":"struct CastRecord\n vote::Vote\n timestamp::DateTime\nend\n\nRepresents a ballotbox ledger record. Adds a timestamp when the vote have been recorded. In future, the record will also contain a blind signature with which members could prove to everyone that they had cast their vote without revealing the link to the vote.\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.Proposal","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Proposal","text":"struct Proposal <: Transaction \n uuid::UUID\n summary::String\n description::String\n ballot::Ballot\n open::DateTime\n closed::DateTime\n collector::Union{Pseudonym, Nothing} # \n anchor::Union{ChainState, Nothing}\n approval::Union{Seal, Nothing} \nend\n\nRepresents a proposal for a ballot specyfing voting window, unique identifier, summary, description. Set's the collector identity which collects votes and issues vote inclusion receipts and is responsable for maintaining the ledger's integrity. The proposal also includes an anchor which sets a relative generator with which members vote anonymously. To be considered valid is signed by proposer authorizing vote to take place.\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.Selection","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Selection","text":"struct Selection\n option::Int\nend\n\nRepresents voter's selection for a Ballot form.\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.Tally","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Tally","text":"struct Tally\n data::Vector{Int}\nend\n\nRepresent a tally for Ballot form obtained aftert counting multiple voter's Selection forms.\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.Model.Vote","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.Vote","text":"struct Vote\n proposal::Digest\n seed::Digest\n selection::Selection\n seq::Int\n approval::Union{Seal, Nothing} \nend\n\nRepresents a vote for a proposal issued by a member. The proposal is stored as hash digest ensuring that member have voted on an untampered proposal. seed contains a randon string issued by collector at the moment when a vote starts to eliminate early voting / shortening a time at which coercers could act uppon. selection contians voter's preference; \n\nseq is a serquence number counting a number of votes at which vote have been approved for a given proposal. It starts at 1 and is increased by one for every single signature made on the proposal. This is an important measure which allows to detect possible leakage of a member's private key. Also provides means for revoting ensuring that latest vote get's counted.\n\nThe vote is considered valid when it is sealed by a member's private key at a relative generator stored in the proposal. \n\n\n\n\n\n","category":"type"},{"location":"model/#HistoryTrees.root-Tuple{PeaceFounder.Core.Model.BallotBoxState}","page":"PeaceFounder.Core.Model","title":"HistoryTrees.root","text":"root(state::BallotBoxState)\n\nReturn a history tree root for a current ballotbox ledger state.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.generator-Tuple{PeaceFounder.Core.Model.Proposal}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.generator","text":"generator(proposal::Proposal)\n\nA relative generator for at which memebers sign votes for this proposal.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.index-Tuple{PeaceFounder.Core.Model.BallotBoxState}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.index","text":"index(state::BallotBoxState)\n\nReturn an index for a current ballotbox ledger state.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.isbinding-Tuple{PeaceFounder.Core.Model.CastReceipt, PeaceFounder.Core.Model.Vote, CryptoGroups.Specs.HashSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.isbinding","text":"isbinding(receipt::CastReceipt, vote::Vote, hasher::HashSpec)::Bool\n\nCheck that the receipt is bidning to a vote. \n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.isbinding-Tuple{PeaceFounder.Core.Model.Vote, PeaceFounder.Core.Model.Proposal, CryptoGroups.Specs.HashSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.isbinding","text":"isbinding(vote::Vote, proposal::Proposal, crypto::HashSpec)\n\nCheck that the vote is bound to a proposal.. \n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.isconsistent-Tuple{PeaceFounder.Core.Model.Selection, PeaceFounder.Core.Model.Ballot}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.isconsistent","text":"isconsistent(selection::Selection, ballot::Ballot)\n\nVerifies that voter's selection is consistent with ballot form. For instance, whether selection is withing the range of ballot options.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.issuer-Tuple{PeaceFounder.Core.Model.Proposal}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.issuer","text":"issuer(proposal::Proposal)\n\nIssuer of approval for the proposal.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.pseudonym-Tuple{PeaceFounder.Core.Model.Vote}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.pseudonym","text":"pseudonym(vote::Vote)::Union{Pseudonym, Nothing}\n\nReturn a pseudonym with which vote is sealed.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.receipt-Tuple{PeaceFounder.Core.Model.CastRecord, CryptoGroups.Specs.HashSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.receipt","text":"receipt(record::CastRecord, hasher::HashSpec)::CastReceipt\n\nConstruct a CastReceipt from a CastRecord with a provided hasher function.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.state","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.state","text":"state(ledger::BallotBoxLedger; seed::Digest, root::Digest = root(ledger), with_tally::Union{Nothing, Bool} = nothing)::BallotBoxState\n\nReturn a state metadata for ballotbox ledger. \n\n\n\n\n\n","category":"function"},{"location":"model/#PeaceFounder.Core.Model.state-Tuple{PeaceFounder.Core.Model.Proposal}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.state","text":"state(proposal::Proposal)::ChainState\n\nA braidchain ledger state which is used to anchor a relative generator for members.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.tally","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.tally","text":"tally(ledger::BallotBox)\n\nCompute a tally for a ballotbox ledger. \n\n\n\n\n\n","category":"function"},{"location":"model/#PeaceFounder.Core.Model.tally-Tuple{PeaceFounder.Core.Model.Ballot, AbstractVector{PeaceFounder.Core.Model.Selection}}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.tally","text":"tally(ballot::Ballot, ballots::AbstractVector{Selection})::Tally\n\nCount ballots, check that they are filled consistently and return a final tally.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.uuid-Tuple{PeaceFounder.Core.Model.Proposal}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.uuid","text":"uuid(proposal::Proposal)::UUID\n\nUUID for a proposal. Issued by proposer and it's purpose is to croslink to an external system durring the proposal dreafting stage.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.vote-Tuple{PeaceFounder.Core.Model.Proposal, PeaceFounder.Core.Model.Digest, PeaceFounder.Core.Model.Selection, PeaceFounder.Core.Model.Signer}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.vote","text":"vote(proposal::Proposal, seed::Digest, selection::Selection, member::Signer; seq = 1)\n\nIssue a vote on a proposal and provided collector seed for a member's selection. \n\n\n\n\n\n","category":"method"},{"location":"model/#Auditing","page":"PeaceFounder.Core.Model","title":"Auditing","text":"","category":"section"},{"location":"model/","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model","text":"Modules = [PeaceFounder.Core.Model]\nOrder = [:type, :function]\nPages = [\"Core/Model/audit.jl\"]","category":"page"},{"location":"model/#PeaceFounder.Core.ProtocolSchema","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.ProtocolSchema","text":"","category":"section"},{"location":"model/","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model","text":"Modules = [PeaceFounder.Core.ProtocolSchema]\nOrder = [:type, :function]","category":"page"},{"location":"model/#PeaceFounder.Core.ProtocolSchema.AckConsistency","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.ProtocolSchema.AckConsistency","text":"struct AckConsistency{T}\n proof::ConsistencyProof\n commit::Commit{T}\nend\n\nRepresents an ackknowledgment from the issuer that a root is permanetly included in the ledger. This acknowledgemnt assures that ledger up to index(ack) is included in the current ledger which has has index index(commit(ack)). This is useful in a combination with AckInclusion to privatelly update it's validity rather than asking an explicit element. Also ensures that other elements in the ledger are not being tampered with.\n\nInterface: root, id, issuer, commit, index, verify\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.ProtocolSchema.AckInclusion","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.ProtocolSchema.AckInclusion","text":"struct AckInclusion{T}\n proof::InclusionProof\n commit::Commit{T}\nend\n\nRepresents an acknowldgment from the issuer that a leaf is permanently included in the ledger. In case the ledger is tampered with this acknowledgement acts as sufficient proof to blame the issuer.\n\nInterface: leaf, id, issuer, commit, index, verify\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.ProtocolSchema.CastAck","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.ProtocolSchema.CastAck","text":"struct CastAck\n receipt::CastReceipt\n ack::AckInclusion{BallotBoxState}\nend\n\nRepresents a reply to a voter when a vote have been included in the ballotbox ledger. Contains a receipt and inlcusion acknowledgment. In future would also include a blind signature in the reply for a proof of participation. To receive this reply (with a blind signature in the future) a voter needs to send a vote which is concealed during ellections and thus tagging votes with blind signatures from reply to monitor revoting would be as hard as monitoring the submitted votes.\n\n\n\n\n\n","category":"type"},{"location":"model/#PeaceFounder.Core.ProtocolSchema.TicketStatus","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.ProtocolSchema.TicketStatus","text":"struct TicketStatus ticketid::TicketID timestamp::DateTime admission::Union{Nothing, Admission} end\n\nRepresents a public state of a ticket. See isadmitted method. \n\n\n\n\n\n","category":"type"},{"location":"model/#HistoryTrees.leaf-Tuple{PeaceFounder.Core.ProtocolSchema.AckInclusion}","page":"PeaceFounder.Core.Model","title":"HistoryTrees.leaf","text":"leaf(ack::AckInclusion)\n\nAccess a leaf diggest for which the acknowledgment is made.\n\n\n\n\n\n","category":"method"},{"location":"model/#HistoryTrees.root-Tuple{PeaceFounder.Core.ProtocolSchema.AckConsistency}","page":"PeaceFounder.Core.Model","title":"HistoryTrees.root","text":"root(x::AckConsistency)\n\nAccess a root diggest for which the acknowledgment is made.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.commit-Tuple{PeaceFounder.Core.ProtocolSchema.AckInclusion}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.commit","text":"commit(x)\n\nAccess a commit of an object x. \n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.commit-Tuple{PeaceFounder.Core.ProtocolSchema.CastAck}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.commit","text":"commit(ack::CastAck)\n\nReturn a commit from a CastAck.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.index-Tuple{PeaceFounder.Core.ProtocolSchema.AckConsistency}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.index","text":"index(ack::AckConsistency)\n\nReturn an index for a root at which the consistency proof is made. To obtain the current ledger index use index(commit(ack)).\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.index-Tuple{PeaceFounder.Core.ProtocolSchema.AckInclusion}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.index","text":"index(ack::AckInclusion)::Int\n\nReturn an index at which the leaf is recorded in the ledger. To obtain the current ledger index use index(commit(ack)).\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.isbinding-Tuple{PeaceFounder.Core.Model.CastReceipt, PeaceFounder.Core.ProtocolSchema.AckInclusion, CryptoGroups.Specs.HashSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.isbinding","text":"isbinding(receipt::CastReceipt, ack::AckInclusion, hasher::HashSpec)::Bool\n\nCheck that cast receipt is binding to received inclusion acknowledgment.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.isbinding-Tuple{PeaceFounder.Core.Model.Transaction, PeaceFounder.Core.ProtocolSchema.AckInclusion{PeaceFounder.Core.Model.ChainState}, PeaceFounder.Core.Model.CryptoSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.isbinding","text":"isbinding(record::Transaction, ack::AckInclusion{ChainState}, crypto::CryptoSpec)\n\nA generic method checking whether transaction is included in the braidchain.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.isbinding-Tuple{PeaceFounder.Core.ProtocolSchema.CastAck, PeaceFounder.Core.Model.Proposal, CryptoGroups.Specs.HashSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.isbinding","text":"isbinding(ack::CastAck, proposal::Proposal, hasher::HashSpec)::Bool\n\nCheck that acknowledgment is legitimate meaning that it is issued by a collector listed in the proposal.\n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.Model.verify-Tuple{PeaceFounder.Core.ProtocolSchema.CastAck, PeaceFounder.Core.Model.CryptoSpec}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.Model.verify","text":"verify(ack::CastAck, crypto::CryptoSpec)::Bool\n\nVerify the cast acknowledgment cryptographic signature. \n\n\n\n\n\n","category":"method"},{"location":"model/#PeaceFounder.Core.ProtocolSchema.isadmitted-Tuple{PeaceFounder.Core.ProtocolSchema.TicketStatus}","page":"PeaceFounder.Core.Model","title":"PeaceFounder.Core.ProtocolSchema.isadmitted","text":"isadmitted(status::TicketStatus)\n\nCheck whether ticket is addmitted. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers","text":"","category":"section"},{"location":"controllers/#Registrar","page":"PeaceFounder.Server.Controllers","title":"Registrar","text":"","category":"section"},{"location":"controllers/","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers","text":"Modules = [PeaceFounder.Server.Controllers]\nOrder = [:type, :function]\nPages = [\"Server/Controllers/registrar.jl\"]","category":"page"},{"location":"controllers/#PeaceFounder.Server.Controllers.Registrar","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.Registrar","text":"struct Registrar\n metadata::Ref{Vector{UInt8}} \n tickets::Vector{Ticket}\n signer::Signer\n hmac::HMAC\nend\n\nRepresents a state for token registrar service. To initialize the service it's necessary to create a signer who can issue a valid admisssion certificates and a secret key with which a recruit client can exchange authorized messages. See also method generate(Registrar, spec).\n\nMetadata is used as means to securelly deliver to the client most recent server specification. \n\nInterface: select, hmac, hasher, key, id, tickets, in, enlist!, admit!, isadmitted, ticket_status\n\n\n\n\n\n","category":"type"},{"location":"controllers/#PeaceFounder.Server.Controllers.Ticket","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.Ticket","text":"mutable struct Ticket\n const ticketid::TicketID\n timestamp::DateTime\n attempt::UInt8\n token::Digest\n tokenid::String # \n admission::Union{Admission, Nothing}\nend\n\nRepresents a ticket state for ticket with ticketid. timestamp represents time when the ticket have been issued by a registrar client in authorization system of choice, for instance, Registrars.jl; attempt is a counter with which token can be reset which is calculated with token(ticketid, attempt, hmac). Lastly admission contains a certified member pseudonym which was authetificated by the user with token.\n\n\n\n\n\n","category":"type"},{"location":"controllers/#Base.in-Tuple{PeaceFounder.Core.Model.TicketID, PeaceFounder.Server.Controllers.Registrar}","page":"PeaceFounder.Server.Controllers","title":"Base.in","text":"in(ticketid::TicketID, registrar::Registrar)::Bool\n\nReturn true if there already is a ticket with ticketid.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.generate-Tuple{Type{PeaceFounder.Server.Controllers.Registrar}, PeaceFounder.Core.Model.CryptoSpec}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.generate","text":"generate(Registrar, spec::CryptoSpec)\n\nGenerate a new token registrar with unique signer and athorization key.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.select-Tuple{Type{PeaceFounder.Core.Model.Admission}, PeaceFounder.Core.Model.Pseudonym, PeaceFounder.Server.Controllers.Registrar}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.select","text":"select(Admission, ticketid::TicketID, registrar::Registrar)::Union{Admission, Nothing}\n\nReturn admission for a ticket with given a given identity pseudonym from registrar. If no ticket with given id is found OR ticket is not yet admitted returns nothing.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.select-Tuple{Type{PeaceFounder.Core.Model.Admission}, PeaceFounder.Core.Model.TicketID, PeaceFounder.Server.Controllers.Registrar}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.select","text":"select(Admission, ticketid::TicketID, registrar::Registrar)::Union{Admission, Nothing}\n\nReturn admission for a ticket with given ticketid from registrar. If no ticket with given ticketid is found OR ticket is not yet admitted returns nothing.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.select-Tuple{Type{PeaceFounder.Server.Controllers.Ticket}, Function, PeaceFounder.Server.Controllers.Registrar}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.select","text":"select(T, predicate::Function, registrar::Registrar)::Union{T, Nothing}\n\nFrom a list of all registrar tickets return T <: Union{Ticket, Admission} for which predicate is true. If none succeds returns nothing.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.ProtocolSchema.isadmitted-Tuple{PeaceFounder.Core.Model.TicketID, PeaceFounder.Server.Controllers.Registrar}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.ProtocolSchema.isadmitted","text":"isadmitted(ticketid::TicketID, registrar::Registrar)\n\nCheck whether a ticket is already admitted. Returns false when either ticket is nonexistent or it's admission is nothing.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.admit!-Tuple{PeaceFounder.Server.Controllers.Registrar, PeaceFounder.Core.Model.Pseudonym, PeaceFounder.Core.Model.TicketID}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.admit!","text":"admit!(registrar::Registrar, id::Pseudonym, ticketid::TicketID)::Admission\n\nAttempt to admit an identity pseudonym id for ticket ticketid. Authorization is expected to happen at the service layer using provided token in the invite. If a ticket is already registered return admission if it matches the provided id. Otherwise throe an error.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.enlist!-Tuple{PeaceFounder.Server.Controllers.Registrar, PeaceFounder.Core.Model.TicketID, Dates.DateTime}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.enlist!","text":"enlist!(registrar::Registrar, ticketid::TicketID, timestamp::DateTime; route::URI=registrar.route)::Invite\n\nRegisters a new ticket with given TicketID and returns an invite. If ticket is already registered the same invite is returned. Throws an error when ticket is already registered.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.hmac-Tuple{PeaceFounder.Server.Controllers.Registrar}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.hmac","text":"hmac(x)::HMAC\n\nReturn HMAC authorizer from a given object.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.set_demehash!-Tuple{PeaceFounder.Server.Controllers.Registrar, PeaceFounder.Core.Model.Digest}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.set_demehash!","text":"set_demespec!(registrar::Registrar, spec::Union{Digest, DemeSpec})\n\nReplace metadata for a registrar. Note when data is replaced all unfinalized tokens need to be flushed. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.ticket_status-Tuple{PeaceFounder.Core.Model.TicketID, PeaceFounder.Server.Controllers.Registrar}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.ticket_status","text":"ticket_status(ticketid::TicketID, registrar::Registrar)::Union{TicketStatus, Nothing}\n\nReturn a ticket status for a ticketid. In case ticket is not found return nothing.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.tickets-Tuple{PeaceFounder.Server.Controllers.Registrar}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.tickets","text":"tickets(registrar::Registrar)::Vector{TicketID}\n\nReturn a list of registered ticket ids. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.token-Tuple{PeaceFounder.Core.Model.TicketID, UInt8, CryptoGroups.Specs.HashSpec, Vector{UInt8}}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.token","text":"token(ticketid::TicketID, hmac::HMAC)\n\nCompute a recruit token for a given ticketid. Calculates it as token=Hash(Hash(0|key)|attempt|ticketid) where attempt is a counter for which token is issued.\n\nNote: the token generation from key is made in order to support it's local computation on a remote server where QR code for registration is shown within organization website.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#BraidChain","page":"PeaceFounder.Server.Controllers","title":"BraidChain","text":"","category":"section"},{"location":"controllers/","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers","text":"Modules = [PeaceFounder.Server.Controllers]\nOrder = [:type, :function]\nPages = [\"Server/Controllers/braidchain.jl\"]","category":"page"},{"location":"controllers/#PeaceFounder.Server.Controllers.BraidChainController","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.BraidChainController","text":"struct BraidChain\n members::Set{Pseudonym}\n ledger::BraidChainLedger\n spec::DemeSpec\n generator::Generator\n tree::HistoryTree\n commit::Union{Commit{ChainState}, Nothing}\nend\n\nRepresents a braidchain ledger with it's associated state. Can be instantitated with a demespec file using BraidChain(::DemeSpec) method.\n\nInterface: push!, record!, state, length, list, select, roll, constituents, generator, commit, commit_index, ledger, leaf, root, ack_leaf, ack_root, members, commit!\n\n\n\n\n\n","category":"type"},{"location":"controllers/#Base.push!-Tuple{PeaceFounder.Server.Controllers.BraidChainController, PeaceFounder.Core.Model.Transaction}","page":"PeaceFounder.Server.Controllers","title":"Base.push!","text":"push!(ledger::BraidChainController, t::Transaction)\n\nAdd an element to the BraidChainController bypassing transaction verification with the chain. This should only be used when the ledger is loaded from a trusted source like a local disk or when final root hash is validated with a trusted source.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#HistoryTrees.leaf-Tuple{PeaceFounder.Server.Controllers.BraidChainController, Int64}","page":"PeaceFounder.Server.Controllers","title":"HistoryTrees.leaf","text":"leaf(ledger::BraidChainController, N::Int)::Digest\n\nReturn a ledger's element digest at given index.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#HistoryTrees.root-Tuple{PeaceFounder.Server.Controllers.BraidChainController}","page":"PeaceFounder.Server.Controllers","title":"HistoryTrees.root","text":"root(ledger::BraidChainController[, N::Int])::Digest\n\nReturn a ledger root digest. In case when index is not given a current index is used.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.commit-Tuple{PeaceFounder.Server.Controllers.BraidChainController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.commit","text":"commit(ledger::BraidChainController)\n\nReturn a current commit for a braichain. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.generator-Tuple{PeaceFounder.Server.Controllers.BraidChainController, Int64}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.generator","text":"generator(ledger[, index])\n\nReturn a generator at braidchain ledger row index. If index is omitted return the current state value.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.generator-Tuple{PeaceFounder.Server.Controllers.BraidChainController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.generator","text":"generator(ledger::BraidChainController)\n\nReturn a current relative generator for a braidchain ledger.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.isbinding-Tuple{PeaceFounder.Server.Controllers.BraidChainController, PeaceFounder.Core.Model.ChainState}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.isbinding","text":"isbinding(chain::BraidChainController, state::ChainState)::Bool\n\nCheck that chain state is consistent with braidchain ledger.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.members-Tuple{PeaceFounder.Server.Controllers.BraidChainController, Int64}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.members","text":"members(chain::BraidChainController, [n::Int])::Set\n\nReturn a set of member pseudonyms which at given anchor index can participate in voting or braiding.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.select-Union{Tuple{T}, Tuple{Type{T}, Function, PeaceFounder.Server.Controllers.BraidChainController}} where T<:PeaceFounder.Core.Model.Transaction","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.select","text":"select(T, predicate::Function, ledger::BraidChainController)::Union{T, Nothing}\n\nReturn a first element from a ledger with a type T which satisfies a predicate. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.state-Tuple{PeaceFounder.Server.Controllers.BraidChainController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.state","text":"state(ledger::BraidChainController)\n\nReturn a current braidchain ledger state metadata.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.ack_leaf-Tuple{PeaceFounder.Server.Controllers.BraidChainController, Int64}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.ack_leaf","text":"ack_leaf(ledger::BraidChainController, index::Int)::AckInclusion\n\nReturn a proof for record inclusion with respect to a current braidchain ledger history tree root. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.ack_root-Tuple{PeaceFounder.Server.Controllers.BraidChainController, Int64}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.ack_root","text":"ack_root(ledger::BraidChainController, index::Int)\n\nReturn a proof for the ledger root at given index with respect to the current braidchain ledger history tree root.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.commit!-Tuple{PeaceFounder.Server.Controllers.BraidChainController, PeaceFounder.Core.Model.Signer}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.commit!","text":"commit!(ledger::BraidChainController, signer::Signer)\n\nCommit a current braidchain ledger state with a signer's issued cryptographic signature. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.constituents-Tuple{PeaceFounder.Server.Controllers.BraidChainController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.constituents","text":"constituents(ledger::BraidChainController)::Set{Pseudonym}\n\nReturn all member identity pseudonyms. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.list-Union{Tuple{T}, Tuple{Type{T}, PeaceFounder.Server.Controllers.BraidChainController}} where T<:PeaceFounder.Core.Model.Transaction","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.list","text":"list(T, ledger::BraidChainController)::Vector{Tuple{Int, T}}\n\nList braidchain elements with a given type together with their index.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.reset_tree!-Tuple{PeaceFounder.Server.Controllers.BraidChainController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.reset_tree!","text":"reset_tree!(ledger::BraidChainController)\n\nRecompute a chain tree hash. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.roll-Tuple{PeaceFounder.Server.Controllers.BraidChainController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.roll","text":"roll(ledger::BraidChainController)::Vector{Membership}\n\nReturn all member certificates from a braidchain ledger.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#BallotBox-and-PollingStation","page":"PeaceFounder.Server.Controllers","title":"BallotBox and PollingStation","text":"","category":"section"},{"location":"controllers/","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers","text":"Modules = [PeaceFounder.Server.Controllers]\nOrder = [:type, :function]\nPages = [\"Server/Controllers/ballotbox.jl\"]","category":"page"},{"location":"controllers/#PeaceFounder.Server.Controllers.BallotBoxController","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.BallotBoxController","text":"mutable struct BallotBoxController\n ledger::BallotBoxLedger\n voters::Set{Pseudonym} # better than members\n collector::Pseudonym\n seed::Union{Digest, Nothing}\n queue::Vector{Vote}\n tree::HistoryTree\n commit::Union{Commit{BallotBoxState}, Nothing}\nend\n\nRepresents a ballot box for a proposal. Contains proposal, a set of eligiable voters a collector who collects the votes and a seed which is selected at random when the voting starts. queue contains a list of valid votes which yet to be comitted to a ledger. A history tree is built on leafs of ledger's receipts (see a receipt method). A commit contains a collector seal on the current ballotbox state. \n\nInterface: reset_tree!, generator, uuid, ledger, spine, index, seed, leaf, root, receipt, commit, tally, set_seed!, ack_leaf, ack_root, ack_cast, commit_index, commit_state, push!, state, validate, record!, commit!\n\n\n\n\n\n","category":"type"},{"location":"controllers/#PeaceFounder.Server.Controllers.PollingStation","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.PollingStation","text":"struct PollingStation\n halls::Vector{BallotBoxController}\n crypto::CryptoSpec\nend\n\nRepresents a pooling station which hosts ballotbox ledgers for every proposal collector manages. \n\nInterface: init!, record!, commit!, commit, ack_leaf, ack_root, ack_cast, receipt, spine, ledger, tally, set_seed!\n\n\n\n\n\n","category":"type"},{"location":"controllers/#Base.get-Tuple{PeaceFounder.Server.Controllers.PollingStation, Base.UUID}","page":"PeaceFounder.Server.Controllers","title":"Base.get","text":"get(station::PollingStation, uuid::UUID)::BallotBoxController\n\nReturn a ballotbox ledger with a provided UUID. If none is found throws an error.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#Base.get-Tuple{PeaceFounder.Server.Controllers.PollingStation, PeaceFounder.Core.Model.Digest}","page":"PeaceFounder.Server.Controllers","title":"Base.get","text":"get(station::PollingStation, proposal::Digest)::BallotBoxController\n\nReturn a ballotbox which has proposal with provided digest.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#Base.getindex-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, Int64}","page":"PeaceFounder.Server.Controllers","title":"Base.getindex","text":"getindex(ledger::BallotBoxController, index::Int)::CastRecord\n\nReturn a ledger record at provided index.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#Base.length-Tuple{PeaceFounder.Server.Controllers.BallotBoxController}","page":"PeaceFounder.Server.Controllers","title":"Base.length","text":"length(ledger::BallotBoxController)\n\nReturn a total length of the ledger including uncommited records in the queue.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#Base.push!-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, PeaceFounder.Core.Model.CastRecord}","page":"PeaceFounder.Server.Controllers","title":"Base.push!","text":"push!(ledger::BallotBoxController, record::CastRecord)\n\nPush a record to the ledger bypassing integrity checks. Used when loading the ledger from a trusted source such as local disk or an archive with a signed root cheksum.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#HistoryTrees.leaf-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, Int64}","page":"PeaceFounder.Server.Controllers","title":"HistoryTrees.leaf","text":"leaf(ledger::BallotBoxController, N::Int)::Digest\n\nReturn a record digest used to form a history tree.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#HistoryTrees.root-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, Int64}","page":"PeaceFounder.Server.Controllers","title":"HistoryTrees.root","text":"root(ledger::BallotBoxController[, N::Int])::Digest\n\nCalculate a root for history tree at given index N. If index is not specified returns the current value.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.commit-Tuple{PeaceFounder.Server.Controllers.BallotBoxController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.commit","text":"commit(ledger::BallotBoxController)\n\nReturn a commit for the ballotbox ledger.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.commit-Tuple{PeaceFounder.Server.Controllers.PollingStation, Base.UUID}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.commit","text":"commit(station::PollingStation, uuid::UUID)::Commit\n\nReturn a ballotbox commit.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.generator-Tuple{PeaceFounder.Server.Controllers.BallotBoxController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.generator","text":"generator(ledger::BallotBoxController)\n\nReturn a relative generator which members use to sign votes anchored by the proposal.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.index-Tuple{PeaceFounder.Server.Controllers.BallotBoxController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.index","text":"index(ledger::BallotBoxController)\n\nReturn the current index of the ledger. See also length.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.isbinding-Tuple{PeaceFounder.Core.Model.Vote, PeaceFounder.Core.ProtocolSchema.CastAck, PeaceFounder.Core.Model.CryptoSpec}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.isbinding","text":"isbinding(vote::Vote, ack::CastAck, hasher)\n\nCheck whether acknowledgment is bound to the provided vote.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.receipt-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, Int64}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.receipt","text":"receipt(ledger::BallotBoxController, index::Int)::CastReceipt\n\nReturn a receipt for a ledger element.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.receipt-Tuple{PeaceFounder.Server.Controllers.PollingStation, Base.UUID, Int64}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.receipt","text":"receipt(station::PollingStation, uuid::UUID, N::Int)::CastReceipt\n\nReturn a receipt for a record with index N at ballotbox with uuid.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.seed-Tuple{PeaceFounder.Server.Controllers.BallotBoxController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.seed","text":"seed(ledger::BallotBoxController)::Union{Digest, Nothing}\n\nReturn a random selected seed used in the voting.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.tally-Tuple{PeaceFounder.Server.Controllers.PollingStation, Base.UUID}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.tally","text":"tally(station::PollingStation, uuid::UUID)\n\nCompute a tally from ledger records a ballotbox with uuid.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.uuid-Tuple{PeaceFounder.Server.Controllers.BallotBoxController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.uuid","text":"uuid(ledger::BallotBoxController)\n\nReturn a UUID of the proposal.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Core.Model.voters-Tuple{PeaceFounder.Server.Controllers.BallotBoxController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Core.Model.voters","text":"voters(ledger::BallotBoxController)\n\nReturn a list of member pseudonyms with which members authetificate their votes.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.ack_cast-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, Int64}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.ack_cast","text":"ack_cast(ledger::BallotBoxController, index::Int)::CastAck\n\nCompute an acknowledgment for record inclusion at index.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.ack_cast-Tuple{PeaceFounder.Server.Controllers.PollingStation, Base.UUID, Int64}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.ack_cast","text":"ack_cast(station::PollingStation, uuid::UUID, N::Int)::CastAck\n\nReturn inclusion proof with receipt and current tree commit for a leaf at index N and ballotbox with uuid. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.ack_leaf-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, Int64}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.ack_leaf","text":"ack_leaf(ledger::BallotBoxController, index::Int)::AckInclusion\n\nCompute an inclusion proof ::AckInclusion for record element at given index.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.ack_leaf-Tuple{PeaceFounder.Server.Controllers.PollingStation, Base.UUID, Int64}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.ack_leaf","text":"ack_leaf(station::PollingStation, uuid::UUID, N::Int)::AckInclusion\n\nReturn history tree inclusion proof for a tree leaf at index N in ballotbox with uuid.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.ack_root-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, Int64}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.ack_root","text":"ack_root(ledger::BallotBoxController, index::Int)::AckConsistency\n\nCompute a history tree consistency proof at index. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.ack_root-Tuple{PeaceFounder.Server.Controllers.PollingStation, Base.UUID, Int64}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.ack_root","text":"ack_root(station::PollingStation, uuid::UUID, N::Int)::AckConsistency\n\nReturn history tree consitency proof tree root at index N in ballotbox with uuid.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.commit!-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, Dates.DateTime, PeaceFounder.Core.Model.Signer}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.commit!","text":"commit!(ledger::BallotBoxController[, timestamp::DataTime], signer::Signer; with_tally=nothing)\n\nFlushes ballotbox ledger's queue and creates a commit for a current ballotbox ledger state with provided timestamp and signer. A keyword argument with_tally has three values true|false to include or exclude a tally from a commited state and nothing which uses a previous commit preference.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.commit!-Tuple{PeaceFounder.Server.Controllers.PollingStation, Base.UUID, PeaceFounder.Core.Model.Signer}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.commit!","text":"commit!(station::PollingStation, uuid::UUID, collector::Signer; with_tally = nothing)\n\nSelect a ballotbox with provided uuid and commit it's state with collector. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.commit_index-Tuple{PeaceFounder.Server.Controllers.BallotBoxController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.commit_index","text":"commit_index(ledger::BallotBoxController)::Union{Index, Nothing}\n\nIndex at which commit is issued. See also length and index\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.commit_state-Tuple{PeaceFounder.Server.Controllers.BallotBoxController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.commit_state","text":"commit_state(ledger::BallotBoxController)\n\nReturn a committed state for a ballotbox ledger.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.init!-Tuple{PeaceFounder.Server.Controllers.PollingStation, PeaceFounder.Core.Model.DemeSpec, PeaceFounder.Core.Model.Proposal, Vector{PeaceFounder.Core.Model.Pseudonym}, PeaceFounder.Core.Model.Pseudonym}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.init!","text":"init!(station::PollingStation, proposal::Proposal, voters::Set{Pseudonym}[, collector::Pseudonym])\n\nCreates a new ballotbox for given proposal with provided member pseudonyms at a relative generator anchored in the proposal. A collector is optional and provided only when it differs from one specified in the proposal. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.ledger-Tuple{PeaceFounder.Server.Controllers.BallotBoxController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.ledger","text":"ledger(ballotbox::BallotBoxController)::Vector{CastRecord}\n\nReturn all records from a ballotbox ledger.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.ledger-Tuple{PeaceFounder.Server.Controllers.PollingStation, Base.UUID}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.ledger","text":"ledger(station::PollingStation, uuid::UUID)::Vector{CastRecord}\n\nReturn a vector of records from a ballotbox with uuid.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.record!-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, PeaceFounder.Core.Model.CastRecord}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.record!","text":"record!(ledger::BallotBoxController, record::CastRecord)\n\nCheck the vote in the record for validity and include that in the ledger directly bypassing queue. This method is useful for replaying and debugging ballotbox ledger state changes. See also record!\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.record!-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, PeaceFounder.Core.Model.Vote}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.record!","text":"record!(ledger::BallotBoxController, vote::Vote)\n\nCheck the vote for validity and pushes it to the queue. Returns an index N at which the vote will be recorded in the ledger. See also push!\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.record!-Tuple{PeaceFounder.Server.Controllers.PollingStation, Base.UUID, PeaceFounder.Core.Model.Vote}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.record!","text":"record!(station::PollingStation, uuid::UUID, vote::Vote)::Int\n\nRecords a vote in a ballotbox with provided proposal UUID. Throws an error if a ballotbox can't be found.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.record!-Tuple{PeaceFounder.Server.Controllers.PollingStation, PeaceFounder.Core.Model.Vote}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.record!","text":"record!(station::PollingStation, uuid::UUID, vote::Vote)::Int\n\nRecord a vote in a ballotbox found by proposal diggest stored in the vote. Throws an error if a ballotbox can't be found.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.reset_tree!-Tuple{PeaceFounder.Server.Controllers.BallotBoxController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.reset_tree!","text":"reset_tree!(ledger::BallotBoxController)\n\nRecompute history tree root and cache from the elements in the ledger. This is a useful for loading the ledger all at once. \n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.set_seed!-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, PeaceFounder.Core.Model.Digest}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.set_seed!","text":"set_seed!(ledger::BallotBoxController, seed::Digest)\n\nSet's a seed of the ballotbox.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.set_seed!-Tuple{PeaceFounder.Server.Controllers.PollingStation, Base.UUID, PeaceFounder.Core.Model.Digest}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.set_seed!","text":"set_seed!(station::PollingStation, uuid::UUID, seed::Digest)\n\nSets a seed for a ballotbox with provided uuid.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.spine-Tuple{PeaceFounder.Server.Controllers.BallotBoxController}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.spine","text":"spine(ledger::BallotBoxController)::Vector{Digest}\n\nReturn a history tree leaf vector.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.spine-Tuple{PeaceFounder.Server.Controllers.PollingStation, Base.UUID}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.spine","text":"spine(station::PollingStation, uuid::UUID)::Vector{Digest}\n\nReturn a leaf vector for a ballotbox with proposal uuid.\n\n\n\n\n\n","category":"method"},{"location":"controllers/#PeaceFounder.Server.Controllers.validate-Tuple{PeaceFounder.Server.Controllers.BallotBoxController, PeaceFounder.Core.Model.Vote}","page":"PeaceFounder.Server.Controllers","title":"PeaceFounder.Server.Controllers.validate","text":"validate(ledger::BallotBoxController, vote::Vote)\n\nCheck that vote can be included in the ballotbox. Is well formed, signed by a member pseudonym and cryptographic signature is valid. Raises error if either of checks fail.\n\n\n\n\n\n","category":"method"},{"location":"client/#Client","page":"Client","title":"Client","text":"","category":"section"},{"location":"client/","page":"Client","title":"Client","text":"The PeaceFounder client can be installed on all major desktop platforms by simply downloading a bundle for your particular platform from the PeaceFounderClient release page. Currently, for demonstration purposes, the application does not save a state. Also, errors should be appropriately handled. For instance, receiving an incorrect receipt or proof from the bulletin board will crash the application. This will be solved in future versions of the client.","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"In the future, the focus will be on mobile applications for iOS and Android. Unfortunately, in the current state, deploying mobile applications with Julia is not possible due to JIT compilation. This is why the client backend is planned to be rewritten in Rust while keeping the QML facade already written. This will be a significant time investment; thus, I would be eager to test the PeaceFounder voting system in practice with the desktop GUI client only to gauge people's needs.","category":"page"},{"location":"client/#For-Developers","page":"Client","title":"For Developers","text":"","category":"section"},{"location":"client/","page":"Client","title":"Client","text":"The PeaceFounder client is implemented in a QML and is available on all major desktop platforms. To run the client, install a recent Julia version on your computer, clone a https://github.com/PeaceFounder/PeaceFounderGUI repository, and run the GUI application with the following:","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"julia --load main.jl","category":"page"},{"location":"client/#Registration-to-a-Deme","page":"Client","title":"Registration to a Deme","text":"","category":"section"},{"location":"client/","page":"Client","title":"Client","text":"The first step for the peacefounder voting system as a potential voter is to enrol in a deme. A deme is an organisational body that maintains the electoral roll of its members and puts proposals to members for a vote. After the person has enrolled and become a member, they can access proposals. It is, however, crucial that only proposals announced after the member registration are available for a vote as the registered member's pseudonym needs to be anonymised first through braiders with other members[1]. ","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"[1]: This could be amended in future versions of the PeaceFounder if this becomes a significant dealbreaker for usability. In such a scenario, a member who registers late would sign votes with their identity pseudonym, and the votes could be tallied together with pseudonymously signed ones but never published on the bulletin board. ","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"
\n \n
Left: an example invite email sent by the Recruiters.jl service. Right: PeaceFounder QML client application at the home screen where the invite can be used to register as member to the Deme. On mobile, a QR code could be scanned instead.
\n
","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"The registration procedure starts with requesting an invite. The invite can be requested from an organisation website, which could show it on the screen, or it can be sent to the email as shown in the figure above. The invite is then scanned in the PeaceFounder client application, which does heavy registration work - generates private and public key pairs, spends an assigned token, authorises the public key, and gets a corresponding admission certificate, which finally is used to catch up with a current relative generator and issue a member certificate which is submitted to the braidchain for inclusion. Since the invite contains a hash digest of the demespec file, registration can be performed under an unsecured channel, making TLS certificate setup redundant for the PeaceFounder service.","category":"page"},{"location":"client/#Voting-on-a-proposal","page":"Client","title":"Voting on a proposal","text":"","category":"section"},{"location":"client/","page":"Client","title":"Client","text":"The member’s identity is represented as a row index in the braidchain storing the member record. This avoids presenting users with overwhelming public keys and lets them grasp their registration status. It also indicates to the voter the minimum anchor index at which the new member can vote on the proposal.","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"
\n \n
Left: a deme view where member’s identity is 21 and the current braidchain state is 89. Two proposals are listed with different states. Right: A selected proposal view. This time, it is not votable by the member as the proposal anchor is 4, whereas the member index is 21. (Images need to be updated for consistency)
\n
","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"When a voter enters the proposal within the specified time window, it can go to ballot view by pressing Vote Now. The ballot view depends on the kind of Ballot used in the proposal. Since the votes are plaintext messages signed with pseudonyms, there are unlimited types of ballots that PeaceFounder can support, like - cardinal, preferential or budget-constrained ballots, some of which are planned to be implemented in the future.","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"A guard report is shown to the voter when the vote is cast. The guard contains three categories:","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"Ballot Box: the deme UUID and a proposal’s record index on the braidchain, after which the elections can be found online.\nA receipt contains the pseudonym hash with which the vote is being cast, the timestamp on when it was recorded in the ballot box, and the cast record gives an index at which the vote is recorded in the ledger.\nA commit contains a current Merkle tree root and index of the collector signed chain. This is also an index at which consistency proof is being checked so that votes can only be removed from the ballot box after they are added with evidence.","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"
\n \n
Left: a view for multiple question ballot. Right: a guard view where the voter sees ballot box identifier, a receipt for casting a vote and a commit of the current state of the ballot box.
\n
","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"The Merkle tree inclusion and consistency proof as a receipt to make a tamper-resistant bulletin board monitored by voters. So that undesirable votes can not be discarded when they have been recorded.","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"After the elections, each voter's client device checks whether the last cast vote is included in the final tally, together with a sequence number on the vote that prevents an adversary that has obtained the voter's private key from casting votes on voters' behalf without being noticed. This is done automatically as long as the client's device acts honestly, i.e., is not infected with malware.","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"In the case of malware, the fairness property maintained by the election authority and a timestamp on the casting receipt prevent malware on the voter's client from pointing to a substitute vote. Whereas the vote is cast as intended and counted as cast (important for revoting), a voter can check on the bulletin board with another computer using the receipt. If the malware is detected, the voter takes appropriate action for his device.","category":"page"},{"location":"schema/#HTTP-API","page":"HTTP","title":"HTTP API","text":"","category":"section"},{"location":"schema/","page":"HTTP","title":"HTTP","text":"\n\n\n\n
\n","category":"page"},{"location":"assets/registration_sequence/","page":"-","title":"-","text":"sequenceDiagram\n participant Client\n participant Registrar\n participant PeaceFounder\n Client->>Registrar: Requests an invite\n Registrar->>PeaceFounder: {ticket_id}_key\n PeaceFounder->>Registrar: {ticket_id, timestamp, demespec, salt}_key\n Registrar->>Client: ticket_id, demespec, token\n Client ->> PeaceFounder: {ticket_id, member_id}_token\n PeaceFounder ->> Client: {member_id}_registrar\n Client ->> PeaceFounder: {pseudonym}_member\n PeaceFounder ->> Client: inclusion_proof, {chain_state}_recorder","category":"page"},{"location":"overview/#Overview","page":"Overview","title":"Overview","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"Note: a more recent and condensed overview is provided in a poster presented at EVoteID 2023","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"
\n \n
A knot like structure formed in a braiding process. On the left, inputs are shown a set of pseudonyms and a relative generator $g$. On the right, the outputs are shuffled pseudonyms, and relative generator exponentiated with a secret factor $s$. The knot itself represents a zero knowledge proof assuring that output pseudonyms are computed correctly without allowing to link input to output pseudonyms. Since $h=g^s$ then $(g^{x_i})^s = (g^s)^{x_i} = h^{x_i}$ which can be computed by private key $x_i$ owners.
\n
","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The core primitive for the PeaceFounder voting system revolves around the ability to generate digital signatures using a single private key for distinct generators, all while maintaining the security of the key. The signatures in such cases are supplemented with a corresponding public key for a relative generator at which the signature has been issued. A relationship between these public keys can be established by showing an exponent connecting the relative generators or forming zero-knowledge proof demonstrating the equality of discrete logarithms. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The concept of unlinkability can be harnessed to create an interconnected structure using multiple private keys resembling a knot. In this structure, input pseudonyms—public keys derived by exponentiating input relative generator with private keys—are bound to output pseudonyms. To achieve this, a dealer exponentiates a relative generator and pseudonyms with the same secret exponent and then shuffles the resulting output pseudonym list. We shall refer to this procedure as braiding to distinguish that from mixing objectives where input retains the original form after going through a mix cascade. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"To ensure integrity in resulting braids, in particular, that braider had not replaced output pseudonyms with its own, zero-knowledge proofs can be used. This can be done by reformulating exponentiation as ElGamal re-encryption shuffle and consequent decryption as recently proposed in a novel e-voting system design. The zero-knowledge proof of shuffle has been successfully made widely available for ElGamal re-encryption mixnets with Verificatum, which offers proof with relatively standard cryptographic assumptions on the difficulty of computing discrete logarithms and a decisional Diffie Hellman assumption. Combined with zero knowledge proof of correct decryption, a braid proof can be formed, proving to everyone that computations have been performed honestly without revealing the secret exponentiation factor braider had used and can be safely forgotten afterwards. The resulting braid primitive is available in the ShuffleProofs.jl package, which also reimplements Verificatum-compatible proof of shuffle in Julia. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The braid primitive enables anonymisation to be transactional with one braider at a time, thus eliminating the need for complex coordination of parties as it is typical for many re-encryption mixnet or homomorphic-based e-voting systems. In addition, it's also possible to publish this evidence on a bulletin board for everyone to verify without compromising participation privacy.","category":"page"},{"location":"overview/#Bulletin-Board","page":"Overview","title":"Bulletin Board","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"
\n \n
High-level diagram of the PeaceFounder system. With a blue colour, the internal components of the peacefounder system are indicated, which are necessary to bootstrap the system. The arrows represent dependencies for producing trust in the election process. Services like TOR and DRAND are shown for context and currently are not integrated.
\n
","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The PeaceFounder's bulletin board is a microservice that accepts transactional records and votes. The primary transactional records include member certificates issued in prospective member interaction with the registrar, braid records which recompute pseudonym member list and corresponding relative generator issued by a braider and proposal records announcing a vote issued by a proposer. The system is configured with a guardian issued deme[1] record, which sets cryptographic parameters, and a rooster, which includes the proposer, registrar, and bulletin board authority identities. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"[1]: The term deme here denotes a PeaceFounder instance for a specific organisation. It is inspired by its historical significance in Ancient Greece, where a deme represented a local administrative unit with its own diverse decision-making structure and governance rules.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The peacefounder bulletin board, proposer, and registrar microservices are internal and can be managed or delegated by a guardian. This separation accommodates customisation for varied political consensus, criteria for proposal submissions to the ballot box, choice of identity provider, and methods for disclosing registrar information to auditors to verify the authenticity of members. To make testing and deployment easier for new organisations, a bundle that includes a registrar, proposer and bulletin board will be available and deployable on a preferred server of choice and will offer web access for a guardian with sane defaults and configuration options.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Member's client devices actively monitor the bulletin board, ensuring the immutability of records by tracking bulletin board commits. This method of oversight is scalable, as members only request a history tree[2] consistency proofs, eliminating the need to replicate the actual bulletin board records. These proofs guarantee the protection of their votes and others, assuring that modifications to records are prevented when fresh entries are appended to the bulletin board. This streamlined approach enables prompt identification of bulletin board dishonesty, whether through removing or altering records or the malicious creation of a counterfeit ledger to exclude undesirable votes from the official tally.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"[2]: A history tree is a specialised Merkle tree designed to track chronological changes, enabling efficient and secure state verification at any historical point.","category":"page"},{"location":"overview/#Auditing","page":"Overview","title":"Auditing","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"Integral to establishing trust, a pivotal role is the presence of an {\\bf auditor}. The auditor is a judicial-like entity representing members and is vital for resolving conflicts. Member client devices create local proofs for altered or removed records or the presence of a counterfeit ledger, which are then sent to the auditor. Moreover, if votes aren't delivered, the auditor can act as a proxy, offering evidence that the bulletin board deliberately omitted specific votes. The auditor also ensures the integrity of the bulletin board's records, confirming each vote's eligibility and unlinkability and ensuring one vote per member.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Notably, the auditor can avoid a formal association with the guardian to verify the integrity of a resulting tally, as all relevant data is on the public bulletin board (except for the registration roll). This autonomy allows members the freedom to select their trusted auditors. If there are unresolved disputes with the bulletin board, members can even take on the auditor role and, if necessary, seek to replace the guardian. The system's transparency further allows auditors to cross-check each other's findings, promoting accuracy and preventing the spread of false claims.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The auditor plays a key role in assessing the registrar to confirm the authenticity of its members. The registrar maintains a registration roll, serving as evidence of every member's authenticity. Authenticity verification can be as simple as a trusted third party's digital signature on a document that includes the organisation's UUID and the index where a member's certificate is recorded. If a third-party identity provider isn't available, a photo or video of an individual displaying a page with the organisation's title and index might suffice. Regardless of the method, the recommended approach is to provide an auditor with a verifiably random subset of members where verifiable randomness, for instance, can be generated with DRAND service to avoid data aggregation.","category":"page"},{"location":"overview/#Coercion-and-bribery-resistance","page":"Overview","title":"Coercion and bribery resistance","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"
\n \n
Illustration of time restricted receipt freeness in the Peacefounder voting system. During the election period, the system maintains both receipt-freeness and fairness. However, after the tally is published, newly submitted votes lose their fairness. The votes themselves can be published on the buletin board latter to extend the time period for receipt-freeness, reducing the effectiveness of coercers and bribers. This comes at the expense of delaying the audit process for verifying that votes have been tallied as cast.
\n
","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Another pillar that is necessary for ensuring democratic elections is to prevent coercion and vote buying. A significant risk to the PeaceFounder system is for a briber to ask members to forward their votes through a proxy channel they control. To counter this threat, the bulletin board hides the actual votes, showing only their hashes, and gives voters an option to revote, ensuring both receipt freeness and vote fairness. A sequence number along the vote ensures that only the latest cast vote on the device matters. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"This method undermines the confidence of vote buyers and coercers, as it prevents them from ensuring that the votes they've acquired will be counted in the final tally. As a consequence, they can only return bribes after votes are published on the bulletin board. (During the vote, only receipt hashes are published on the bulletin board. This serves to both commit the votes while maintaining fairness and receipt-freeness.) This arrangement erodes the credibility of bribers and coercers, making it less likely for voters to engage with them in such transactions due to the lack of a guaranteed positive/negative outcome.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"A secondary concern is the potential for a coercer to ask an individual to show how they had voted on their device. To address this, only a receipt is shown. However, this receipt can be linked to the specific vote on the bulletin board. If coercion becomes a significant threat, the receipt can be visible only briefly, such as 30 minutes after casting a vote. During this window, members can manually record their details in a logbook. While this approach may reduce user-friendliness, it still serves as a robust deterrent against malware.","category":"page"},{"location":"overview/#Malware-and-spyware-detection","page":"Overview","title":"Malware and spyware detection","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"(Image: A PICTURE WITH A RECEIPT)","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The last piece of the puzzle is malware and spyware resistance. An adversary could issue votes without compromising the voter's device in case of key leakage. To counter this, every vote includes a sequence number, which records evidence on the bulletin board when a vote is cast from the voter's device. Moreover, if a vote with a sequence number of one is already on the ledger, the first will override any subsequent vote with the same sequence number. This mechanism prevents malware from silently replacing inactive voter's choices. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"After voting concludes and the results are published, each voter receives a bitmask of the votes included in the final tally, along with consistency proofs. Given that this approach is scalable (e.g., 1kB can handle 8192 votes, and bit compression can further reduce size), voters device's compare this bitmask with the index from their most recent vote receipt. This allows them to detect any malware activity and display an alert to the voter.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"To ensure the voting process's integrity, the voter's device must remain trustworthy. With the presence of malware, there's a risk that the device could falsely reassure the voter that their vote is cast as intended. To counter this threat, after the vote is submitted, the voter receives a receipt containing a timestamp of the vote's record, the pseudonym under which it was cast, and the index where the vote resides on the ledger. Once voting concludes and all votes are disclosed on the bulletin board, the voter can cross-reference their receipt with the bulletin board, verifying that the vote at the provided index aligns with their choice and matches the timestamp when the vote was cast, as well as checking that it was included in the final tally. By maintaining a written record, voters can ensure the accuracy of their vote, safeguarding against malware alterations, unauthorised revoting, or any attempts to redirect multiple voters to a singular vote. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"However, it's essential to acknowledge that voters can only detect malware interference post-vote when comparing their receipt to the bulletin board. Additionally, a voter cannot provide evidence to others that their vote was compromised by malware, which means these instances aren't audited within the PeaceFounder system. As a result, members are encouraged and are responsible for utilising more secure devices less susceptible to malware attacks. For more advanced threats, like a briber mandating malware installation for monitoring or extracting the master key, the use of tamper-resistant hardware becomes essential – an extension larger organisations or states might consider.","category":"page"},{"location":"overview/#Implementation-details-and-responsibilities","page":"Overview","title":"Implementation details and responsibilities","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"(Image: )","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"To illustrate the responsibilities of different entities and the structure of the communication channels, we've provided a detailed diagram. In this representation, arrows indicate which entity holds responsibility for specific resources. The primary mode of communication is facilitated through JSON within an HTTP request/reply. The JSON is also chosen as a canonical byte string format for data signing, which is selected over the ASN1 DER format due to development resource constraints.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The architecture bifurcates the bulletin board into two distinct ledgers: the braidchain and the ballot boxes. This differentiation arises from the disparate pacing and metadata requirements of records. Additionally, casting votes remains inconsequential to the braidchain's state, justifying the ledger division.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Authorised entities, namely the braidchain recorder and the ballot box collector, as specified in the guardian-issued DemeSpec record, oversee each ledger. These controllers uphold the integrity of newly added records, ensuring their coherence with the existing state. For instance, votes must adhere to a specified time window and need to be appropriately signed with member pseudonyms. Braidchain transactions demand more intricate state management, which will be described later. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"In the diagram, arrows necessitating anonymous channels are designated with a TOR label originating from the member. This is a countermeasure against potential adversaries attempting to link votes to members via IP addresses. Although alternative network anonymising solutions exist, TOR is the most prominent, and together with the recent release of the Arti project for Rust, it is ideal for client-side applications [...].","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Members can view the bulletin board records through the HTTP Facade, which displays them in a browser-friendly HTML. This provides a secondary channel to verify that votes are cast as intended and counted as cast. A pure JavaScript-based HTTP facade is possible, which can be hosted on a static website, simplifying deployment. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"It's imperative to recognise the absence of TLS in all communications. This choice stems from the fact that data from the bulletin board is supported with a signature on Merkle tree root, rendering requests tamper-proof. Moreover, using TLS session resumption for anonymous interactions between members and the bulletin board would unintentionally make the system vulnerable to DDOS attacks during the key establishment phase. Furthermore, eliminating the need for certificate issuance and management streamlines system maintenance and deployment, enhancing usability.","category":"page"},{"location":"overview/#Planed-Core-Features","page":"Overview","title":"Planed Core Features","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"The PeaceFounder system is actively focusing on integrating key features in its upcoming iterations to enhance transparency. While not exhaustive, the current list includes well-defined proposals ready for implementation.","category":"page"},{"location":"overview/#PeaceFounderBB","page":"Overview","title":"PeaceFounderBB","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"https://github.com/PeaceFounder/PeaceFounder.jl/issues/22","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"A small democratic community often faces the challenge of limited resources, particularly when it comes to hosting bulletin board data or maintaining a comprehensive website for public record access. However, a recent trend offers a practical solution with static website hosting platforms. These platforms allow the creation of a static website directly from source code stored in a git repository without the hassle of setting up and managing certificates. A popular example is GitHub Pages, which simplifies deployment using action scripts to compile websites from sources.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Integrating a GitHub workflow to compile a webpage makes it an ideal platform for hosting a bulletin board interface. This setup has a dual advantage. The GitHub repository can serve as an authentic storage space for bulletin board records. Secondly, these records are easily accessible to the public via a web interface. Continuous integration further enhances this with build scripts, ensuring the integrity and verification of the bulletin board's contents. Those interested in verifying the bulletin board's integrity independently can either fork the repository and run the action script or clone the data locally.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Additionally, the use of the Zenodo repository enriches this system. Zenodo provides excellent archival workflows and the capability to generate a DOI link. This link serves a similar purpose to dataset references in scientific research, offering a reliable and citable record.","category":"page"},{"location":"overview/#Cast-as-intended-verification-during-the-vote","page":"Overview","title":"Cast as intended verification during the vote","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"https://github.com/PeaceFounder/PeaceFounder.jl/issues/21","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"At present, voters can only confirm that their vote has been cast as intended and accurately counted after the vote has ended and the votes are published. As the publication of votes can be delayed as a measure against coercion, it might discourage voters' participation from verifying that their vote is indeed cast as intended and counted as cast. The key issue lies in the possibility of unnoticed malware on voting devices. If voters don't verify their votes, the likelihood of malware affecting a significant number of votes without detection increases. Thus, having a procedure that enables immediate verification of the voting process is essential to engage more voters to check their votes.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The PeaceFounder system can address this by providing voters with a token displayed on the client's screen for vote verification. This token can be used in a web browser to confirm that the vote has been cast as intended. It also indicates if the vote has been superseded by a subsequent vote or one with a higher sequence number, which may occur if the member's key is compromised. To maintain receipt-freeness, the token remains valid for only a short period, such as 15 minutes. The expiration is crucial; it allows voters to verify their votes while preventing coercion or bribery attempts. It also hinders any unsolicited checks on voters' choices.","category":"page"},{"location":"overview/#Evidence-auditing-with-terminal-API","page":"Overview","title":"Evidence auditing with terminal API","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"https://github.com/PeaceFounder/PeaceFounder.jl/issues/19","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The PeaceFounder system is universally verifiable, a feature ensuring that every vote is cryptographically proven to come from a registered member, even if all involved parties are corrupt. To mitigate the influence of coercion or bribery, the authority can strategically delay the publication of votes, which weakens the link between coercers and their subjects before the voters lose receipt freeness. After the votes are published, every aspect of the voting process is transparent: all proofs of votes are made publicly available. This transparency allows any interested party to audit the election results and, at their convenience, independently reproduce the announced tally.","category":"page"},{"location":"overview/#Membership-Termination","page":"Overview","title":"Membership Termination","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"https://github.com/PeaceFounder/PeaceFounder.jl/issues/18","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Under the current state of PeaceFounder, administrators face a significant limitation: they lack the capability to terminate memberships. This function is crucial in various scenarios. For instance, when a member fails to submit necessary authenticity documents within the allotted time post-registration, their membership must be annulled. Additionally, this feature is vital for addressing privacy concerns, such as when members wish to withdraw and have their associated records deleted. Furthermore, an essential aspect of membership management involves issuing new credentials in cases where a member loses their device or experiences a security breach with their key being compromised.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The process of terminating a membership in PeaceFounder presents its own set of challenges. The core difficulty lies in the inability to link a member's real identity and their current pseudonym, which prevents the removal of it in subsequent braidings. This link is only known exclusively to the member's client device, as it only knows the private key that can generate them.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"A straightforward approach to address this issue involves resetting the generator in the braidchain and taking identity pseudonyms of the membership certificates as inputs to subsequent braidings. However, this method presents a significant hurdle, particularly for larger organisations. Implementing this reset each time a member is terminated can be prohibitively expensive. In particular, taking into account that the frequency of membership termination cases increases proportionally with the number of members as well as the required compute to do braidings, making this approach to scale as O(N^2). Therefore, a more sophisticated and nuanced solution is needed.","category":"page"},{"location":"overview/#Extensions","page":"Overview","title":"Extensions","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"In order to avoid over-commitment, the peacefounder project currently focuses on smaller-scale organisations. This implies that a single developer must be able to maintain the system, that coercion/bribery is not of the utmost importance, and that the electoral roll is not necessary to satisfy the requirements of a law. Thus, those features are not integrated into the current design and can be considered separately as system extensions.","category":"page"},{"location":"overview/#Proof-of-participation","page":"Overview","title":"Proof of participation","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"https://github.com/PeaceFounder/PeaceFounder.jl/issues/12","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Some communities may wish to nudge their members to vote, providing benefits for those who have already cast a vote or punishing those who ignore democratic decision-making. In ordinary e-voting systems, that can be easily achieved through a voter’s registry. However, this is not possible for PeaceFounder because voters are completely anonymous when they cast a vote.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"One way to address this issue is with a blind signature scheme. The voter takes his identity pseudonym, blinds it with a random factor and includes that in the vote when sent to the ballot box. The collector checks that the vote is valid and, if so, signs the blinded group element at the time when the vote is recorded in the ledger. The blind signature is reused if the voter has already cast a ballot.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The voter then receives an acknowledgement that the vote is permanently recorded in the chain together with the blind signature and timestamp. The voter unblinds the blind signature with its blinding factor and obtains a signature on his identity pseudonym as proof of participation. That can then be safely shown publicly for anyone who wants to see that the person has voted without being linked to the cast vote.","category":"page"},{"location":"overview/#Selection's-asymmetric-encryption","page":"Overview","title":"Selection's asymmetric encryption","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"https://github.com/PeaceFounder/PeaceFounder.jl/issues/16","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"To maintain the impartiality of auditors/monitors with regard to votes they oversee and further deter potential bribery attempts, an asymmetric encryption method for vote selection is advisable. Under this protocol, the voter's device encrypts a symmetric key asymmetrically and then proceeds to encrypt the vote selection using this symmetric key. The key and the encrypted selection are included in the vote, which is then signed using a pseudonym. Upon receiving the vote, after authenticating its signature, the system decrypts the symmetric key, followed by the vote selection. To ensure the decryption's integrity, a zero-knowledge proof is provided and subsequently published alongside the vote on the bulletin board.","category":"page"},{"location":"overview/#Coerced-vote-tagging","page":"Overview","title":"Coerced vote tagging","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"https://github.com/PeaceFounder/PeaceFounder.jl/issues/16","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"A threat where coercers forcibly dictate voters' choices while confiscating their devices is a pressing concern beyond the PeaceFounder system. A common solution to such a problem is equipping voters with an option to create a secondary PIN code, which works exactly as the primary PIN code except that the votes are tagged as coerced. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"To safeguard against coercers potentially discerning this distinction using a proxy vote submission method, the coercion tag can be asymmetrically encrypted as a group element before transmitting it to the ballot box collector. Upon receipt, the collector would record and then decrypt the coercion tag. A zero-knowledge proof of decryption would ensure the collector's integrity, published together with a vote on the bulletin board. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Votes are disclosed at the conclusion of the process, indicating any tags applied. By lengthening the gap between the tally announcement and the release of the votes, we can diminish the impact of coercive threats and deter unscrupulous voters from awaiting compensation, hinging on the assumption of the briber's credibility. Technically, this mechanism ensures receipt freeness until they appear on the ballot box ledger.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"This strategy presumes that no adversarial entity has infiltrated the collector system. To mitigate such risks, deploying multiple collectors, to which voters are randomly pre-assigned, is advised. This introduces a level of inter-collector accountability, as aggregated results should align. Notably, while receipt freeness is limited, the method retains full transparency: all parties can validate the tally's accuracy and verify every vote's eligibility and unlinkability, as well as the validity of the coercion tag. ","category":"page"},{"location":"overview/#Sempled-Electoral-Roll-Audits","page":"Overview","title":"Sempled Electoral Roll Audits","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"https://github.com/PeaceFounder/PeaceFounder.jl/issues/17","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"In order to ensure the integrity of elections, it is crucial that independent auditors audit the legitimacy of members. However, the records that support the membership cannot be made public as it would violate the members' right to freedom of association and would also infringe on GDPR. Keeping these records confidential while ensuring they are sufficiently audited can be challenging and may require reducing openness to prevent any possible leaks.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"To overcome this dilemma in favour of more openness, a sampling of the electoral roll could be used. A large enough sample size can provide sufficient confidence that a potentially corrupt registrar could not have affected the election result, whereas keeping it small reduces the impact of leaks from the auditors. This lowers the trust barrier and opens the electoral roll auditing for more independent parties.","category":"page"},{"location":"overview/#Early-leaked-private-key-detection","page":"Overview","title":"Early leaked private key detection","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"In a situation where the adversary has acquired a member's private key, they can form valid votes that can be included in the bulletin board. To detect that a bitmask is included in the ballot box commit, which the voter retrieves together with consistency proofs. That allows us to see whether tallied votes have been cast from the member's device as it can look into the bitmask for tallied votes after the vote. However, when a member votes after the adversary, the bulletin board could inform about the fact in the receipt.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The problem is that showing on receipt whether the vote is a final submission considered for inclusion in the tally can impede the voter's ability to revote if the coercer/briber waits until the last minute before submitting their acquired vote. This circumvents a measure where publishing votes is delayed for an extended time after the tally is published for eroding trust in bribers and delaying punishment from coercers. Therefore, the response status needs to be asymmetrically encrypted. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"The status code can be encrypted as a group element and decrypted on the voter's device. If the submitted vote is not final, the collector encrypts a group element representing status addressed to the pseudonym that cast the vote. The device receives the receipt, and as it only has the private key, the status code can be shown. That allows members to see early whether the vote was already cast with the provided sequence number and superseded it with possible recasting. ","category":"page"},{"location":"overview/#Sharded-Ballots","page":"Overview","title":"Sharded Ballots","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"In democratic processes, it's conceivable that voters may be presented with an extensive list of ballot questions to express their opinions. However, as evident with comprehensive surveys, there is a noticeable decline in response rates as the number of questions escalates. Further complicating matters is the phenomenon known as the 'voter's paradox,' wherein the impact of a singular vote diminishes in larger elections. Both challenges can be addressed by sharding lengthy ballots among the entire voter base. ","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"In the PeaceFounder system, sharding is trivial due to votes being cast pseudonymously. The initial step in the sharding involves determining all feasible divisions of the ballot and methodically enumerating them. Subsequently, these shards are allocated to pseudonyms, achieved by systematically sorting and matching them in sequence.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Nevertheless, a pronounced security concern emerges. Suppose an adversary assumes control over the proposer and possesses knowledge of a select group of pseudonym owners and their inclinations. In that case, they can manipulate the election outcome by tailoring the proposal and shards. Specifically, critical questions can be allocated to a limited cohort, skewing results in their favour.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"To counteract this vulnerability, it's imperative for the proposer to commit to both the ballot and its associated shards, followed by a lottery to randomise the pseudonym list. Leveraging a DRAND service, which collaborates with multiple entities to execute threshold decryption, ensures the generation of predetermined, incorruptible random numbers [...]. These numbers subsequently serve as salt for hashing pseudonyms, which are sorted and allocated to shards accordingly. A critical aspect of this method is making sure the proposal is committed before the lottery result is announced to prevent adversaries from taking advantage of waiting for a favourable lottery outcome. This necessitates the involvement of auditors/monitors to timestamp the braidchain ledger commitments externally.","category":"page"},{"location":"#PeaceFounder.jl","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"","category":"section"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"(Image: ) (Image: )","category":"page"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"PeaceFounder is a centralised E2E verifiable e-voting system that leverages pseudonym braiding and history trees. The immutability of the bulletin board is maintained replication-free by voter’s client devices with locally stored consistency-proof chains. Meanwhile, pseudonym braiding done via an exponentiation mix before the vote allows anonymisation to be transactional with a single braider at a time. In contrast to existing E2E verifiable e-voting systems, it is much easier to deploy as the system is fully centralised, free from threshold decryption ceremonies, trusted setup phases and bulletin board replication. Furthermore, the body of a vote is signed with a braided pseudonym, enabling unlimited ballot types.","category":"page"},{"location":"#Introduction","page":"PeaceFounder.jl","title":"Introduction","text":"","category":"section"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"everal end-to-end (E2E) verifiable e-voting systems exist, such as Helios, Scytl, Belenios, ElectionGuard, Estonia's system, and Verificatum, with many available under open-source licences. They all encrypt and mix votes through a re-encryption shuffle and use a threshold decryption ceremony. This allows voters to track their encrypted votes and the public to verify the final tally. However, it depends on the integrity of the bulletin board and the coordination of the threshold decryption ceremony, presenting challenges for smaller communities and organisations.","category":"page"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"To make a point, let's consider a Helios voting system. The vote in Helios is stored in a group element, encrypted and signed by a digital signature provider, and then submitted to the bulletin board. When the vote closes, votes go through the reencryption shuffle and are decrypted in the threshold decryption ceremony. Voters can ensure that their vote has been counted by finding their encrypted vote within the list of inputs of the mix cascade. Furthermore, everyone can verify the final tally by counting the decrypted votes and verifying supplemented zero-knowledge proofs without compromising privacy. In this way, the integrity of the election result can be assured.","category":"page"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"However, issues like forced abstention and potential vote substitution of unverified votes can happen if authorities are corrupt and auditing/monitoring does not occur. Publishing vote-casting signatures can alleviate many of those issues, but that violates participation privacy. The threshold decryption ceremony further compounds the system's complexity; if more than a few are corrupt, votes can remain encrypted, while a low threshold risks privacy breaches. These factors, coupled with the technical intricacies of deployment, make Helios less feasible for small to medium-sized communities, leading to a preference for simpler black box systems to prevent questions from being asked, which can foster trust at the expense of trustworthiness.","category":"page"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"A significant improvement over Helios is the Selene system, which offers a voter-assigned tracking number and shows their votes next to them after the vote. Recent usability studies with Selene have demonstrated that voters appreciate the ability to verify their vote in plaintext. This allows them to discard their trust in advanced cryptography as they can see how their vote is counted. As the tracking number is not published before the vote and is deniable, it is also coercion-resistant. In addition to clever cryptography, it can also detect malware interference. However, the threshold decryption ceremony still needs to be deployed along with the bulletin board and thus would generally suit only state-like elections.","category":"page"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"Haenni & Spycher proposed a system using exponentiation mixes to anonymise voters' pseudonyms, eliminating the need for a threshold decryption ceremony. However, the benefits of such a system have yet to be reaped as it requires a trusted bulletin board that does not discard unfavourable votes; thus, deployment of such a system needs to be distributed and hence offers minor deployment improvements over Helios. Furthermore, over 13 years, a single open-source system has yet to be implemented.","category":"page"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"The innovative approach by PeaceFounder combines pseudonym braiding developed by Haenni & Spycher with a history trees-enabled bulletin board (Crosby & Wallach). When voters cast their vote, their devices receive inclusion proof of the vote, which can later be verified to be binding to the tally with consistency proof. By having only a few voters who request their device to check the proofs, the immutability of the bulletin board is guaranteed. Thus, once the server has assured that the vote is recorded, there is no way for it to be removed. This allows the system to be fully centralised and, thus, makes it easy to self-host.","category":"page"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"However, such a system poses many challenges compared to the orthodox approach. To protect against a corrupt server that discards unfavourable votes, voters must have the option to route the vote through proxy/monitor, which adds a challenge with coercion/bribery. To reap the benefits of braiding pseudonyms with any other community/organisation worldwide, the voters must be registered long before the vote starts, which would produce a bad user experience. Therefore, disengaging anonymisation from voting requires long-standing accounts, which poses an issue for continuous member registration and termination; on top of that, the votes need to be delivered over an anonymous channel not to be traceable by a corrupt authority. All of them are addressed with the PeaceFounder project in innovative ways.","category":"page"},{"location":"#Demo","page":"PeaceFounder.jl","title":"Demo","text":"","category":"section"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"An 8-minute YouTube demonstration is available here:","category":"page"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"(Image: IMAGE ALT TEXT HERE)","category":"page"},{"location":"#References","page":"PeaceFounder.jl","title":"References","text":"","category":"section"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"Rolf Haenni and Oliver Spycher. Secure internet voting on limited devices with anonymized DSA public keys. 2011\nScott A. Crosby and Dan S. Wallach. Efficient data structures for tamper-evident logging. 2009\nBjörn Terelius and Douglas Wikström. Proofs of restricted shuffles. 2010.","category":"page"}] } diff --git a/dev/setup/index.html b/dev/setup/index.html index e6e008e..c15a4d5 100644 --- a/dev/setup/index.html +++ b/dev/setup/index.html @@ -66,4 +66,4 @@ ) |> approve(PROPOSER) -ack = Mapper.submit_chain_record!(proposal)

Notice that state(commit) is added to the proposal. This anchors the relative generator on which the votes are cast.

+ack = Mapper.submit_chain_record!(proposal)

Notice that state(commit) is added to the proposal. This anchors the relative generator on which the votes are cast.