From fb097b3cd6b759b0c93b60505c59633d1e2dbb47 Mon Sep 17 00:00:00 2001 From: "Documenter.jl" Date: Wed, 6 Sep 2023 19:58:18 +0000 Subject: [PATCH] build based on 8140f8d --- dev/assets/registration_sequence/index.html | 2 +- dev/audit/index.html | 2 +- dev/audittools/index.html | 10 +-- dev/client/index.html | 2 +- dev/index.html | 2 +- dev/model_api/index.html | 72 ++++++++++----------- dev/overview/index.html | 2 +- dev/schedulers/index.html | 4 +- dev/schema/index.html | 2 +- dev/search/index.html | 2 +- dev/search_index.js | 2 +- dev/setup/index.html | 2 +- 12 files changed, 52 insertions(+), 52 deletions(-) diff --git a/dev/assets/registration_sequence/index.html b/dev/assets/registration_sequence/index.html index 72b04fa..0878575 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 aa88e70..85452ea 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 3c037f4..996c3ab 100644 --- a/dev/audittools/index.html +++ b/dev/audittools/index.html @@ -16,15 +16,15 @@ @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 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.AuditTools.BallotBoxArchiveType
struct BallotBoxArchive
+@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:

  • Legitimacy: only and all eligiable voters cast their votes;
  • Fairness: every eligiable voter can vote at most once;
  • Immutability: no vote can be deleted or modified when recorded in the ledger;
  • Tallied as Cast: all cast votes are counted honestly to predetermined procedure;
  • Software independence: the previously audited properties for the evidence does not

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.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.AuditTools.BraidChainArchiveType
struct BraidChainArchive
+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.AuditTools.BraidChainArchiveType
struct BraidChainArchive
     ledger::Vector{Transaction}
-end

Represents a braidchain ledger archive.

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

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

source
PeaceFounder.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)
+end

Represents a braidchain ledger archive.

source
PeaceFounder.AuditTools.archiveFunction
archive(ledger::BraidChain)::BraidChainArchive
+archive(ledger::BallotBox)::BallotBoxArchive

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

source
PeaceFounder.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.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.AuditTools.audit_lotsFunction
audit_lots(ledger::BraidChainArchive)

Check integrity correct nonce commitments. Note that it is possible that this will be moved out to a ballotbox ledger in the future. Also service like DRAND would be beneficial to reduce trust assumptions.

source
PeaceFounder.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; - Member approved by a admitted identity only once; - Every member psuedonym is generated with the current relative generator in the braidchain ledger;

source
PeaceFounder.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.AuditTools.audit_rosterFunction
audit_roster(ledger::BraidChainArchive)

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

source
PeaceFounder.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_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.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.AuditTools.audit_lotsFunction
audit_lots(ledger::BraidChainArchive)

Check integrity correct nonce commitments. Note that it is possible that this will be moved out to a ballotbox ledger in the future. Also service like DRAND would be beneficial to reduce trust assumptions.

source
PeaceFounder.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; - Member approved by a admitted identity only once; - Every member psuedonym is generated with the current relative generator in the braidchain ledger;

source
PeaceFounder.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.AuditTools.audit_rosterFunction
audit_roster(ledger::BraidChainArchive)

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

source
PeaceFounder.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
diff --git a/dev/client/index.html b/dev/client/index.html index 266fbda..782b343 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, aka not being infected with malware.

In the case of malware, the fairness property maintained by the election authority and a timestamp on the casting receipt prevents 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, aka not being infected with malware.

In the case of malware, the fairness property maintained by the election authority and a timestamp on the casting receipt prevents 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/index.html b/dev/index.html index bb8473a..b277c3d 100644 --- a/dev/index.html +++ b/dev/index.html @@ -1,2 +1,2 @@ -PeaceFounder.jl · PeaceFounder.jl

PeaceFounder.jl

A major hurdle in mainstream E2E (end-to-end) e-voting system designs is a multiparty protocol ceremony coordination required for initiating a threshold decryption key and performing decryption at the end of the vote. The voter's anonymity demands independence of the involved parties, which introduces a risk of sabotage where election results could be left undecrypted and unannounced. Moreover, due to the need to encode ballot selection in a group element, only a limited number of ballot types can be supported and face challenges, for instance, for cardinal and budget planning ballots. This is even more restrictive when a homomorphic counting procedure is employed.

An alternative approach is to anonymise voter's credentials instead of the votes. The idea has been explored with blind signature schemes, but auditing the authority's issuance of signatures and detecting key leaks remains unresolved. A subsequent method, proposed by Haenni \& Spycher, leverages ElGamal re-encryption to verifiably exponentiate voters' public keys in tandem with a generator using zero-knowledge proofs. Together with a history tree bulletin board implementation, it forms the foundation for the design of the PeaceFounder voting system.

The PeaceFounder voting system builds upon the foundational work of Haenni & Spycher, serving as a practical implementation of their proposal. Nevertheless, PeaceFounder introduces several key features:

  • A scalable bulletin board design with thin-member clients ensuring the immutability of all published records without replication;
  • A registration protocol for new members that catches them up with the current relative generator;
  • Mechanisms to handle uncooperative bulletin boards through auditors/proxies while preventing potential exploitation by coercers and bribers with time-restricted receipt freeness and revoting;
  • A system allowing a member's device to detect private key leaks coming from spyware or bad cryptography via sequence numbers and bitmasks;
  • A malware detection mechanism post-voting, where the device displayed receipt, is compared to a bulletin board while not being deceived into verifying another voter's vote.

Furthermore, PeaceFounder demonstrates that a single maintainer can feasibly deploy the system. That is possible due to the lack of a multi-party ceremony and member device accountability of the bulletin board. It also offers seamless integration opportunities with existing infrastructure and political environment for supporting different ways proposals are put to the ballot box, and member authenticity is verified and later audited. Additionally, the PeaceFounder showcases user experience for the voter, minimising their exposure to complex byte strings while maintaining cryptographic soundness along with other usability improvements.

Demo

For a demo, go to the PeaceFounderDemo repository. A 10-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

A major hurdle in mainstream E2E (end-to-end) e-voting system designs is a multiparty protocol ceremony coordination required for initiating a threshold decryption key and performing decryption at the end of the vote. The voter's anonymity demands independence of the involved parties, which introduces a risk of sabotage where election results could be left undecrypted and unannounced. Moreover, due to the need to encode ballot selection in a group element, only a limited number of ballot types can be supported and face challenges, for instance, for cardinal and budget planning ballots. This is even more restrictive when a homomorphic counting procedure is employed.

An alternative approach is to anonymise voter's credentials instead of the votes. The idea has been explored with blind signature schemes, but auditing the authority's issuance of signatures and detecting key leaks remains unresolved. A subsequent method, proposed by Haenni & Spycher, leverages ElGamal re-encryption to verifiably exponentiate voters' public keys in tandem with a generator using zero-knowledge proofs. Together with a history tree bulletin board implementation, it forms the foundation for the design of the PeaceFounder voting system.

The PeaceFounder voting system builds upon the foundational work of Haenni & Spycher, serving as a practical implementation of their proposal. Nevertheless, PeaceFounder introduces several key features:

  • A scalable bulletin board design with thin-member clients ensuring the immutability of all published records without replication;
  • A registration protocol for new members that catches them up with the current relative generator;
  • Mechanisms to handle uncooperative bulletin boards through auditors/proxies while preventing potential exploitation by coercers and bribers with time-restricted receipt freeness and revoting;
  • A system allowing a member's device to detect private key leaks coming from spyware or bad cryptography via sequence numbers and bitmasks;
  • A malware detection mechanism post-voting, where the device displayed receipt, is compared to a bulletin board while not being deceived into verifying another voter's vote.

Furthermore, PeaceFounder demonstrates that a single maintainer can feasibly deploy the system. That is possible due to the lack of a multi-party ceremony and member device accountability of the bulletin board. It also offers seamless integration opportunities with existing infrastructure and political environment for supporting different ways proposals are put to the ballot box, and member authenticity is verified and later audited. Additionally, the PeaceFounder showcases user experience for the voter, minimising their exposure to complex byte strings while maintaining cryptographic soundness along with other usability improvements.

Demo

For a demo, go to the PeaceFounderDemo repository. A 10-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_api/index.html b/dev/model_api/index.html index db9aa35..dbb3efb 100644 --- a/dev/model_api/index.html +++ b/dev/model_api/index.html @@ -2,71 +2,71 @@ PeaceFounder.Model · PeaceFounder.jl

PeaceFounder.Model

Primitives

PeaceFounder.Model.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.Model.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.Model.AckInclusionType
struct AckInclusion{T}
     proof::InclusionProof
     commit::Commit{T}
-end

Represents 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.

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

source
PeaceFounder.Model.CommitType
Commit{T}
+end

Represents 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.

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

source
PeaceFounder.Model.CryptoSpecType
struct CryptoSpec
     hasher::Hash
     group::Spec
     generator::Generator
-end

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

source
PeaceFounder.Model.DigestType
struct Digest
+end

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

source
PeaceFounder.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.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.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
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.Model.digestMethod
digest(message::Vector{UInt8}, hasher::Hash)::Digest
-digest(document, spec) = digest(canonicalize(message)::Vector{UInt8}, hasher(spec)::Hash)

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

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

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

source
PeaceFounder.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.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.Model.isbindingMethod
isbinding(x, y, spec::Hash)::Bool
-isbinding(x, y, spec) = isbinding(x, y, hasher(spec)::Hash)

Check binding of two objects x and y. Some general examples:

  • Check that a document is bound to it's signature.
  • Check that a record is included in the ledger.
  • Check that a given object is consistent with a ledger.
source
PeaceFounder.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.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.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.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.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.Model.idFunction
id(document)::Pseudonym

Return identity pseudonym of a document issuer.


id(signer)::Pseudonym

Return identity pseudonym of a signer.

source
PeaceFounder.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::BraidWork, crypto::CryptoSpec)::Bool

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

source

Admission

PeaceFounder.Model.AdmissionType
struct Admission
+end

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

Interface: pseudonym, id, sign, seal, approve

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.Model.digestMethod
digest(message::Vector{UInt8}, hasher::Hash)::Digest
+digest(document, spec) = digest(canonicalize(message)::Vector{UInt8}, hasher(spec)::Hash)

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

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

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

source
PeaceFounder.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.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.Model.isbindingMethod
isbinding(x, y, spec::Hash)::Bool
+isbinding(x, y, spec) = isbinding(x, y, hasher(spec)::Hash)

Check binding of two objects x and y. Some general examples:

  • Check that a document is bound to it's signature.
  • Check that a record is included in the ledger.
  • Check that a given object is consistent with a ledger.
source
PeaceFounder.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.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.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.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.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.Model.idFunction
id(document)::Pseudonym

Return identity pseudonym of a document issuer.


id(signer)::Pseudonym

Return identity pseudonym of a signer.

source
PeaceFounder.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::BraidWork, crypto::CryptoSpec)::Bool

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

source

Admission

PeaceFounder.Model.TicketType
mutable struct Ticket
     const ticketid::TicketID
     timestamp::DateTime
     salt::Vector{UInt8}
     auth_code::Digest
     token::Digest
     admission::Union{Admission, Nothing}
-end

Represents a ticket state for ticket with ticketid. timestamp represents time when the ticket have been issued by a recruiter client in authorization system of choice, for instance, Recruiters.jl; salt contains a random bytestring generated by the server from which the reccruiter client can derive a token as token(ticketid, salt, hmac). auth_code is a server generated authetification code for a given salt and current metadata. Lastly admission contains a certified member pseudonym which was authetificated by the user with token.

source
PeaceFounder.Model.TicketIDType
struct TicketID
+end

Represents a ticket state for ticket with ticketid. timestamp represents time when the ticket have been issued by a recruiter client in authorization system of choice, for instance, Recruiters.jl; salt contains a random bytestring generated by the server from which the reccruiter client can derive a token as token(ticketid, salt, hmac). auth_code is a server generated authetification code for a given salt and current metadata. Lastly admission contains a certified member pseudonym which was authetificated by the user with token.

source
PeaceFounder.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.Model.TokenRecruiterType
struct TokenRecruiter
+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.Model.TokenRecruiterType
struct TokenRecruiter
     metadata::Ref{Vector{UInt8}} 
     tickets::Vector{Ticket}
     signer::Signer
     hmac::HMAC
-end

Represents a state for token recruiter 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(TokenRecruiter, spec).

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

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

source
Base.inMethod
in(ticketid::TicketID, recruiter::TokenRecruiter)::Bool

Return true if there already is a ticket with ticketid.

source
PeaceFounder.Model.admit!Method
admit!(recruiter::TokenRecruiter, id::Pseudonym, ticketid::TicketID, auth_code::Digest)::Admission

Attempt to admit an identity pseudonym id for ticket ticketid with provided authorization code. This function retrieves a ticket with given ticketid and uses it's recorded token to check whether the request is binding. In the case of success an admnission certificate is formed with provided indenty pseudonym id and is signed by the recruter's private key. Otherwise when either of checks fail an error is raised. In the case ticket is already addmitted, returns previously stored admission.

source
PeaceFounder.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.Model.authMethod
auth(id::Pseudonym, hmac::HMAC)::Digest
-auth(id::Pseudonym, token::Digest, hasher::Hash) = auth(id, HMAC(bytes(token), hasher))

Compute a hash authorization code for identity pseudonym using token as a key.

source
PeaceFounder.Model.authMethod
auth(ticketid::TicketID, time::DateTime, hmac::HMAC)::Digest

Compute a hash authorization code for ticketid at given time. The message needs to reach token recruiter within a 60 second window before it is obseleted.

source
PeaceFounder.Model.authMethod
auth(metadata::Vector{UInt8}, ticketid::TicketID, salt::Vector{UInt8}, hmac::HMAC)::Digest

Compute a hash authorization code for a metadata, salt from which a token is derived. Metadata can be configured to contain most recent server specification DemeSpec; ticketid takes session identifier role.

source
PeaceFounder.Model.enlist!Method
enlist!(recruiter::TokenRecruiter, ticketid::TicketID, timestamp::DateTime, ticket_auth_code::Digest)::Tuple{Vector{UInt8}, Vector{UInt8}, Digest}

Attempt to enlist a ticket with given ticketid authetificated by a recruit client at timestmap. This function checks the age of the request which need to be less than 60 seconds to be considered. Then the hash authorization code is checked after which a triplet of metadata, salt and reply_auth_code is returned. If either of theses checks fail an error is raised and needs to be dealt by the user. See a token method on how the token is derived.

source
PeaceFounder.Model.isadmittedMethod
isadmitted(ticketid::TicketID, recruiter::TokenRecruiter)

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

source
PeaceFounder.Model.isbindingMethod
isbinding(id::Pseudonym, auth_code::Digest, token::Digest, hasher::Hash)

Check whether a request for a new identity pseudonym admission is authetificated. The token is delivered to a user by recruit client.

source
PeaceFounder.Model.isbindingMethod
isbinding(ticketid::TicketID, timestamp::DateTime, auth_code::Digest, hmac::HMAC)

Check whether request for a new ticketid is authorized by recruit client. Note that freshness of the request is not considered within this method.

source
PeaceFounder.Model.isbindingMethod
isbinding(metadata::Vector{UInt8}, ticketid::TicketID, salt::Vector{UInt8}, auth_code::Digest, hmac::HMAC)

Check whether a reply for a new ticketid is authorized by the recruit server.

source
PeaceFounder.Model.selectMethod
select(Admission, ticketid::TicketID, recruiter::TokenRecruiter)::Union{Admission, Nothing}

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

source
PeaceFounder.Model.selectMethod
select(Admission, ticketid::TicketID, recruiter::TokenRecruiter)::Union{Admission, Nothing}

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

source
PeaceFounder.Model.selectMethod
select(T, predicate::Function, recruiter::TokenRecruiter)::Union{T, Nothing}

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

source
PeaceFounder.Model.set_metadata!Method
set_metadata!(recruiter::TokenRecruiter, metadata::Vector{UInt8})

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

source
PeaceFounder.Model.ticket_statusMethod
ticket_status(ticketid::TicketID, recruiter::TokenRecruiter)::Union{TicketStatus, Nothing}

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

source
PeaceFounder.Model.tokenMethod
token(ticketid::TicketID, salt::Vector{UInt8}, hmac::HMAC)

Compute a recruit token for a given ticket with provided salt.

source

BraidChain

PeaceFounder.Model.BraidChainType
struct BraidChain
+end

Represents a state for token recruiter 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(TokenRecruiter, spec).

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

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

source
Base.inMethod
in(ticketid::TicketID, recruiter::TokenRecruiter)::Bool

Return true if there already is a ticket with ticketid.

source
PeaceFounder.Model.admit!Method
admit!(recruiter::TokenRecruiter, id::Pseudonym, ticketid::TicketID, auth_code::Digest)::Admission

Attempt to admit an identity pseudonym id for ticket ticketid with provided authorization code. This function retrieves a ticket with given ticketid and uses it's recorded token to check whether the request is binding. In the case of success an admnission certificate is formed with provided indenty pseudonym id and is signed by the recruter's private key. Otherwise when either of checks fail an error is raised. In the case ticket is already addmitted, returns previously stored admission.

source
PeaceFounder.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.Model.authMethod
auth(id::Pseudonym, hmac::HMAC)::Digest
+auth(id::Pseudonym, token::Digest, hasher::Hash) = auth(id, HMAC(bytes(token), hasher))

Compute a hash authorization code for identity pseudonym using token as a key.

source
PeaceFounder.Model.authMethod
auth(ticketid::TicketID, time::DateTime, hmac::HMAC)::Digest

Compute a hash authorization code for ticketid at given time. The message needs to reach token recruiter within a 60 second window before it is obseleted.

source
PeaceFounder.Model.authMethod
auth(metadata::Vector{UInt8}, ticketid::TicketID, salt::Vector{UInt8}, hmac::HMAC)::Digest

Compute a hash authorization code for a metadata, salt from which a token is derived. Metadata can be configured to contain most recent server specification DemeSpec; ticketid takes session identifier role.

source
PeaceFounder.Model.enlist!Method
enlist!(recruiter::TokenRecruiter, ticketid::TicketID, timestamp::DateTime, ticket_auth_code::Digest)::Tuple{Vector{UInt8}, Vector{UInt8}, Digest}

Attempt to enlist a ticket with given ticketid authetificated by a recruit client at timestmap. This function checks the age of the request which need to be less than 60 seconds to be considered. Then the hash authorization code is checked after which a triplet of metadata, salt and reply_auth_code is returned. If either of theses checks fail an error is raised and needs to be dealt by the user. See a token method on how the token is derived.

source
PeaceFounder.Model.isadmittedMethod
isadmitted(ticketid::TicketID, recruiter::TokenRecruiter)

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

source
PeaceFounder.Model.isbindingMethod
isbinding(id::Pseudonym, auth_code::Digest, token::Digest, hasher::Hash)

Check whether a request for a new identity pseudonym admission is authetificated. The token is delivered to a user by recruit client.

source
PeaceFounder.Model.isbindingMethod
isbinding(ticketid::TicketID, timestamp::DateTime, auth_code::Digest, hmac::HMAC)

Check whether request for a new ticketid is authorized by recruit client. Note that freshness of the request is not considered within this method.

source
PeaceFounder.Model.isbindingMethod
isbinding(metadata::Vector{UInt8}, ticketid::TicketID, salt::Vector{UInt8}, auth_code::Digest, hmac::HMAC)

Check whether a reply for a new ticketid is authorized by the recruit server.

source
PeaceFounder.Model.selectMethod
select(Admission, ticketid::TicketID, recruiter::TokenRecruiter)::Union{Admission, Nothing}

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

source
PeaceFounder.Model.selectMethod
select(Admission, ticketid::TicketID, recruiter::TokenRecruiter)::Union{Admission, Nothing}

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

source
PeaceFounder.Model.selectMethod
select(T, predicate::Function, recruiter::TokenRecruiter)::Union{T, Nothing}

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

source
PeaceFounder.Model.set_metadata!Method
set_metadata!(recruiter::TokenRecruiter, metadata::Vector{UInt8})

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

source
PeaceFounder.Model.ticket_statusMethod
ticket_status(ticketid::TicketID, recruiter::TokenRecruiter)::Union{TicketStatus, Nothing}

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

source
PeaceFounder.Model.tokenMethod
token(ticketid::TicketID, salt::Vector{UInt8}, hmac::HMAC)

Compute a recruit token for a given ticket with provided salt.

source

BraidChain

PeaceFounder.Model.BraidChainType
struct BraidChain
     members::Set{Pseudonym}
     ledger::Vector{Transaction}
     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
PeaceFounder.Model.DemeSpecType
struct DemeSpec <: Transaction
     uuid::UUID
     title::String
     crypto::CryptoSpec
@@ -78,19 +78,19 @@
     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};
    • recruiter::Pseudonym an authorithy which has rights to authorize new admissions to the deme. See Admission and Member;
    • braider::Pseudonym an authorithy which can do a legitimate braid jobs for other demes. See BraidWork;
    • 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.Model.MemberType
struct Member <: 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};
    • recruiter::Pseudonym an authorithy which has rights to authorize new admissions to the deme. See Admission and Member;
    • braider::Pseudonym an authorithy which can do a legitimate braid jobs for other demes. See BraidWork;
    • 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.Model.MemberType
struct Member <: 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
Base.push!Method
push!(ledger::BraidChain, t::Transaction)

Add an element to the BraidChain 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::BraidChain, N::Int)::Digest

Return a ledger's element digest at given index.

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

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

source
PeaceFounder.Model.ack_leafMethod
ack_leaf(ledger::BraidChain, index::Int)::AckInclusion

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

source
PeaceFounder.Model.ack_rootMethod
ack_root(ledger::BraidChain, index::Int)

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

source
PeaceFounder.Model.commit!Method
commit!(ledger::BraidChain, signer::Signer)

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

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

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

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

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

source
PeaceFounder.Model.listMethod
list(T, ledger::BraidChain)::Vector{Tuple{Int, T}}

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

source
PeaceFounder.Model.membersMethod
members(ledger::BraidChain[, 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.Model.selectMethod
select(T, predicate::Function, ledger::BraidChain)::Union{T, Nothing}

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

source
PeaceFounder.Model.BraidWorkType
struct BraidWork <: Transaction
+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
Base.push!Method
push!(ledger::BraidChain, t::Transaction)

Add an element to the BraidChain 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::BraidChain, N::Int)::Digest

Return a ledger's element digest at given index.

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

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

source
PeaceFounder.Model.ack_leafMethod
ack_leaf(ledger::BraidChain, index::Int)::AckInclusion

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

source
PeaceFounder.Model.ack_rootMethod
ack_root(ledger::BraidChain, index::Int)

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

source
PeaceFounder.Model.commit!Method
commit!(ledger::BraidChain, signer::Signer)

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

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

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

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

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

source
PeaceFounder.Model.listMethod
list(T, ledger::BraidChain)::Vector{Tuple{Int, T}}

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

source
PeaceFounder.Model.membersMethod
members(ledger::BraidChain[, 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.Model.selectMethod
select(T, predicate::Function, ledger::BraidChain)::Union{T, Nothing}

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

source
PeaceFounder.Model.BraidWorkType
struct BraidWork <: Transaction
     braid::Simulator
     consumer::DemeSpec
     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; consumer denotes a deme for which the braid is intended and 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.Model.approveMethod
approve(braid::BraidWork, braider::Signer)

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

source
PeaceFounder.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.Model.verifyMethod
verify(braid::BraidWork, 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.Model.BallotType
struct Ballot
+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; consumer denotes a deme for which the braid is intended and 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.Model.approveMethod
approve(braid::BraidWork, braider::Signer)

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

source
PeaceFounder.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.Model.verifyMethod
verify(braid::BraidWork, 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.Model.BallotBoxType
mutable struct BallotBox
     proposal::Proposal
     voters::Set{Pseudonym} # better than members
     collector::Pseudonym
@@ -100,26 +100,26 @@
     ledger::Vector{CastRecord}
     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, members, ledger, spine, index, seed, leaf, root, record, receipt, commit, tally, set_seed!, ack_leaf, ack_root, ack_cast, commit_index, commit_state, push!, state, validate, record!, commit!

source
PeaceFounder.Model.BallotBoxStateType
struct BallotBoxState
+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, members, ledger, spine, index, seed, leaf, root, record, receipt, commit, tally, set_seed!, ack_leaf, ack_root, ack_cast, commit_index, commit_state, push!, state, validate, record!, commit!

source
PeaceFounder.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.Model.CastAckType
struct CastAck
+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.Model.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
PeaceFounder.Model.CastReceiptType
struct CastReceipt
+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.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.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.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.Model.PollingStationType
struct PollingStation
+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.Model.ProposalType
struct Proposal <: Transaction 
     uuid::UUID
     summary::String
     description::String
@@ -129,14 +129,14 @@
     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.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.Model.TallyType
struct Tally
     data::Vector{Int}
-end

Represent a tally for Ballot form obtained aftert counting multiple voter's Selection forms.

source
PeaceFounder.Model.VoteType
struct Vote
+end

Represent a tally for Ballot form obtained aftert counting multiple voter's Selection forms.

source
PeaceFounder.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
Base.lengthMethod
length(ledger::BallotBox)

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

source
Base.push!Method
push!(ledger::BallotBox, 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::BallotBox, N::Int)::Digest

Return a record digest used to form a history tree.

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

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

source
HistoryTrees.rootMethod
root(state::BallotBoxState)

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

source
PeaceFounder.Model.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.Model.ack_leafMethod
ack_leaf(ledger::BallotBox, index::Int)::AckInclusion

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

source
PeaceFounder.Model.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.Model.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.Model.add!Method
add!(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.Model.ballotboxMethod
ballotbox(station::PollingStation, uuid::UUID)::BallotBox

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

source
PeaceFounder.Model.commit!Method
commit!(ledger::BallotBox[, 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.Model.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.Model.isbindingMethod
isbinding(ack::CastAck, proposal::Proposal, hasher::Hash)::Bool

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

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

Check that cast receipt is binding to received inclusion acknowledgment.

source
PeaceFounder.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.Model.ledgerMethod
ledger(station::PollingStation, uuid::UUID)::Vector{CastRecord}

Return a vector of records from a ballotbox with uuid.

source
PeaceFounder.Model.receiptMethod
receipt(record::CastRecord, hasher::Hash)::CastReceipt

Construct a CastReceipt from a CastRecord with a provided hasher function.

source
PeaceFounder.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.Model.record!Method
record!(ledger::BallotBox, 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.Model.record!Method
record!(ledger::BallotBox, 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.Model.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.Model.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.Model.recordMethod
record(station::PollingStation, uuid::UUID, N::Int)::CastRecord

Return a record with an index N at ballotbox with uuid.

source
PeaceFounder.Model.reset_tree!Method
reset_tree!(ledger::BallotBox)

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.Model.spineMethod
spine(station::PollingStation, uuid::UUID)::Vector{Digest}

Return a leaf vector for a ballotbox with proposal uuid.

source
PeaceFounder.Model.stateMethod
state(ledger::BallotBox; with_tally::Union{Nothing, Bool} = nothing)::BallotBoxState

Return a state metadata for ballotbox ledger.

source
PeaceFounder.Model.stateMethod
state(proposal::Proposal)::ChainState

A braidchain ledger state which is used to anchor a relative generator for members.

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

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

source
PeaceFounder.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.Model.validateMethod
validate(ledger::BallotBox, 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
PeaceFounder.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
+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
Base.lengthMethod
length(ledger::BallotBox)

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

source
Base.push!Method
push!(ledger::BallotBox, 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::BallotBox, N::Int)::Digest

Return a record digest used to form a history tree.

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

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

source
HistoryTrees.rootMethod
root(state::BallotBoxState)

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

source
PeaceFounder.Model.ack_castMethod
ack_cast(ledger::BallotBox, index::Int)::CastAck

Compute an acknowledgment for record inclusion at index.

source
PeaceFounder.Model.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.Model.ack_leafMethod
ack_leaf(ledger::BallotBox, index::Int)::AckInclusion

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

source
PeaceFounder.Model.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.Model.ack_rootMethod
ack_root(ledger::BallotBox, index::Int)::AckConsistency

Compute a history tree consistency proof at index.

source
PeaceFounder.Model.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.Model.add!Method
add!(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.Model.ballotboxMethod
ballotbox(station::PollingStation, uuid::UUID)::BallotBox

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

source
PeaceFounder.Model.ballotboxMethod
ballotbox(station::PollingStation, proposal::Digest)::BallotBox

Return a ballotbox which has proposal with provided digest.

source
PeaceFounder.Model.commit!Method
commit!(ledger::BallotBox[, 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.Model.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.Model.commitMethod
commit(ledger::BallotBox)

Return a commit for the ballotbox ledger.

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

Return a commit from a CastAck.

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

Return a ballotbox commit.

source
PeaceFounder.Model.commit_indexMethod
commit_index(ledger::BallotBox)::Union{Index, Nothing}

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

source
PeaceFounder.Model.commit_stateMethod
commit_state(ledger::BallotBox)

Return a committed state for a ballotbox ledger.

source
PeaceFounder.Model.generatorMethod
generator(ledger::BallotBox)

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

source
PeaceFounder.Model.generatorMethod
generator(proposal::Proposal)

A relative generator for at which memebers sign votes for this proposal.

source
PeaceFounder.Model.indexMethod
index(state::BallotBoxState)

Return an index for a current ballotbox ledger state.

source
PeaceFounder.Model.indexMethod
index(ledger::BallotBox)

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

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

Check that chain state is consistent with braidchain ledger.

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

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

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

Check that cast receipt is binding to received inclusion acknowledgment.

source
PeaceFounder.Model.isbindingMethod
isbinding(receipt::CastReceipt, vote::Vote, hasher::Hash)::Bool

Check that the receipt is bidning to a vote.

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

Check whether acknowledgment is bound to the provided vote.

source
PeaceFounder.Model.isbindingMethod
isbinding(vote::Vote, proposal::Proposal, crypto::CryptoSpec)

Check that the vote is bound to a proposal..

source
PeaceFounder.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.Model.issuerMethod
issuer(proposal::Proposal)

Issuer of approval for the proposal.

source
PeaceFounder.Model.ledgerMethod
ledger(ballotbox::BallotBox)::Vector{CastRecord}

Return all records from a ballotbox ledger.

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

Return a vector of records from a ballotbox with uuid.

source
PeaceFounder.Model.membersMethod
members(ledger::BallotBox)

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

source
PeaceFounder.Model.pseudonymMethod
pseudonym(vote::Vote)::Union{Pseudonym, Nothing}

Return a pseudonym with which vote is sealed.

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

Return a receipt for a ledger element.

source
PeaceFounder.Model.receiptMethod
receipt(record::CastRecord, hasher::Hash)::CastReceipt

Construct a CastReceipt from a CastRecord with a provided hasher function.

source
PeaceFounder.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.Model.record!Method
record!(ledger::BallotBox, 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.Model.record!Method
record!(ledger::BallotBox, 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.Model.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.Model.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.Model.recordMethod
record(ledger::BallotBox, index::Int)::CastRecord

Return a ledger record at provided index.

source
PeaceFounder.Model.recordMethod
record(station::PollingStation, uuid::UUID, N::Int)::CastRecord

Return a record with an index N at ballotbox with uuid.

source
PeaceFounder.Model.reset_tree!Method
reset_tree!(ledger::BallotBox)

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.Model.seedMethod
seed(ledger::BallotBox)::Union{Digest, Nothing}

Return a random selected seed used in the voting.

source
PeaceFounder.Model.set_seed!Method
set_seed!(ledger::BallotBox, seed::Digest)

Set's a seed of the ballotbox.

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

Sets a seed for a ballotbox with provided uuid.

source
PeaceFounder.Model.spineMethod
spine(ledger::BallotBox)::Vector{Digest}

Return a history tree leaf vector.

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

Return a leaf vector for a ballotbox with proposal uuid.

source
PeaceFounder.Model.stateMethod
state(ledger::BallotBox; with_tally::Union{Nothing, Bool} = nothing)::BallotBoxState

Return a state metadata for ballotbox ledger.

source
PeaceFounder.Model.stateMethod
state(proposal::Proposal)::ChainState

A braidchain ledger state which is used to anchor a relative generator for members.

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

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

source
PeaceFounder.Model.tallyMethod
tally(ledger::BallotBox)

Compute a tally for a ballotbox ledger.

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

Compute a tally from ledger records a ballotbox with uuid.

source
PeaceFounder.Model.uuidMethod
uuid(ledger::BallotBox)

Return a UUID of the proposal.

source
PeaceFounder.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.Model.validateMethod
validate(ledger::BallotBox, 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
PeaceFounder.Model.verifyMethod
verify(ack::CastAck, crypto::CryptoSpec)::Bool

Verify the cast acknowledgment cryptographic signature.

source
PeaceFounder.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
diff --git a/dev/overview/index.html b/dev/overview/index.html index 62762d7..7950d4b 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 ma

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.

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

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

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

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.

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 ma

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.

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

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

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

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.

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 545bb6a..1927a3e 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 378ef7e..23622a4 100644 --- a/dev/schema/index.html +++ b/dev/schema/index.html @@ -36,4 +36,4 @@ GET /braider/jobs/{JobID} : JobStatus GET /braider/jobs/{JobID}/braid : Braid POST /braider/jobs : BraidJobSpec -> JobID -PUT /braider/jobs/{JobID} : Tuple{Vector{Pseudonym}, Generator} -> JobStatus +PUT /braider/jobs/{JobID} : Tuple{Vector{Pseudonym}, Generator} -> JobStatus diff --git a/dev/search/index.html b/dev/search/index.html index d045320..60564c5 100644 --- a/dev/search/index.html +++ b/dev/search/index.html @@ -1,2 +1,2 @@ -Search · PeaceFounder.jl

Loading search...

    +Search · PeaceFounder.jl

    Loading search...

      diff --git a/dev/search_index.js b/dev/search_index.js index d62378f..c2b633b 100644 --- a/dev/search_index.js +++ b/dev/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"client/#Client","page":"Client","title":"Client","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/","page":"Client","title":"Client","text":"In the future, a bundle will be available for every major system so that all voters can install the client without technical knowledge. ","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"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 the future versions of the client, which can be accelerated by letting me know if that interests you. ","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"In future, the focus will be on the mobile application 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/#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, aka not being 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 prevents 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/#REST-API","page":"REST","title":"REST API","text":"","category":"section"},{"location":"schema/","page":"REST","title":"REST","text":"This is an approximate rest API for the PeaceFounder. In future, this will be properly generated and documented from the code. ","category":"page"},{"location":"schema/","page":"REST","title":"REST","text":"GET /deme # returns a current manifest file\nGET /deme/{hash}\n\nPOST /tickets : Tuple{TicketID, DateTime, auth_code::Digest} -> Tuple{salt::Vector{UInt8}, auth_code::Digest} # resets token when repeated\nDELETE /tickets/{TicketID}\nPUT /tickets/{TicketID} : Tuple{Pseudonym, auth_code::Digest} -> Admission\nGET /tickets/{TicketID} : TicketStatus\n\nPOST /braidchain/members : Member -> AckInclusion{ChainState}\nGET /braidchain/members : Vector{Tuple{Int, Member}}\nGET /braidchain/members?id={Pseudonym} : Tuple{Int, Member}\nGET /braidchain/members?pseudonym={Pseudonym} : Tuple{Int, Member}\n\nPOST /braidchain/proposals : Proposal -> AckInclusion\nGET /braidcahin/proposals/{UUID} : Tuple{Int, Proposal}\nGET /braidchain/proposals : Vector{Tuple{Int, Proposal}}\n\nGET /braidchain/{Int}/record : Transaction\nGET /braidchain/{Int}/leaf : AckInclusion{ChainState}\nGET /braidchain/{Int}/root : AckConsistency{ChainState}\nGET /braidchain/commit : Commit{ChainState}\nGET /braidchain/tar : BraidChainArchive\n\nPOST /pollingstation/{UUID}/votes : Vote -> CastAck\nGET /pollingstation/{UUID}/spine : Vector{Digest}\nGET /pollingstation/{UUID}/commit : Commit{BallotBoxState}\nGET /pollingstation/{UUID}/proposal : Tuple{Int, Proposal}\nGET /pollingstation/{UUID}/votes/{Int}/record : CastRecord\nGET /pollingstation/{UUID}/votes/{Int}/receipt : CastReceipt\nGET /pollingstation/{UUID}/votes/{Int}/leaf : AckInclusion{BallotBoxState}\nGET /pollingstation/{UUID}/votes/{Int}/root : AckConsistency{BallotBoxState}\nGET /pollingstation/{UUID}/tar : BallotBoxArchive\nGET /pollingstation/collectors # necessary to make a proposal","category":"page"},{"location":"schema/#Braider","page":"REST","title":"Braider","text":"","category":"section"},{"location":"schema/","page":"REST","title":"REST","text":"GET /braider : BraiderStatus\nGET /braider/jobs : Vector{JobID}\nGET /braider/jobs/{JobID} : JobStatus\nGET /braider/jobs/{JobID}/braid : Braid\nPOST /braider/jobs : BraidJobSpec -> JobID\nPUT /braider/jobs/{JobID} : Tuple{Vector{Pseudonym}, Generator} -> JobStatus","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. Currently, the best auditing strategy is to recreate the braidchain and ballotbox 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. Every voter, after elections, 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":"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":"audittools/#PeaceFounder.AuditTools","page":"PeaceFounder.AuditTools","title":"PeaceFounder.AuditTools","text":"","category":"section"},{"location":"audittools/","page":"PeaceFounder.AuditTools","title":"PeaceFounder.AuditTools","text":"PeaceFounder.AuditTools","category":"page"},{"location":"audittools/","page":"PeaceFounder.AuditTools","title":"PeaceFounder.AuditTools","text":"Modules = [PeaceFounder.AuditTools]\nOrder = [:module, :type, :function]","category":"page"},{"location":"audittools/#PeaceFounder.AuditTools","page":"PeaceFounder.AuditTools","title":"PeaceFounder.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.AuditTools.BallotBoxArchive","page":"PeaceFounder.AuditTools","title":"PeaceFounder.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.AuditTools.BraidChainArchive","page":"PeaceFounder.AuditTools","title":"PeaceFounder.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.AuditTools.archive","page":"PeaceFounder.AuditTools","title":"PeaceFounder.AuditTools.archive","text":"archive(ledger::BraidChain)::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.AuditTools.audit","page":"PeaceFounder.AuditTools","title":"PeaceFounder.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.AuditTools.audit_braids","page":"PeaceFounder.AuditTools","title":"PeaceFounder.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.AuditTools.audit_lots","page":"PeaceFounder.AuditTools","title":"PeaceFounder.AuditTools.audit_lots","text":"audit_lots(ledger::BraidChainArchive)\n\nCheck integrity correct nonce commitments. Note that it is possible that this will be moved out to a ballotbox ledger in the future. Also service like DRAND would be beneficial to reduce trust assumptions.\n\n\n\n\n\n","category":"function"},{"location":"audittools/#PeaceFounder.AuditTools.audit_members","page":"PeaceFounder.AuditTools","title":"PeaceFounder.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; - Member 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.AuditTools.audit_proposals","page":"PeaceFounder.AuditTools","title":"PeaceFounder.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.AuditTools.audit_roster","page":"PeaceFounder.AuditTools","title":"PeaceFounder.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.AuditTools.checksum","page":"PeaceFounder.AuditTools","title":"PeaceFounder.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":"overview/#Overview","page":"Overview","title":"Overview","text":"","category":"section"},{"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 ma","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/#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":"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":"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":"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/#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":"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":"model_api/#PeaceFounder.Model","page":"PeaceFounder.Model","title":"PeaceFounder.Model","text":"","category":"section"},{"location":"model_api/#Primitives","page":"PeaceFounder.Model","title":"Primitives","text":"","category":"section"},{"location":"model_api/","page":"PeaceFounder.Model","title":"PeaceFounder.Model","text":"Modules = [PeaceFounder.Model]\nOrder = [:type, :function]\nPages = [\"Model/crypto.jl\", \"Model/seal.jl\"]","category":"page"},{"location":"model_api/#PeaceFounder.Model.AckConsistency","page":"PeaceFounder.Model","title":"PeaceFounder.Model.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_api/#PeaceFounder.Model.AckInclusion","page":"PeaceFounder.Model","title":"PeaceFounder.Model.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_api/#PeaceFounder.Model.Commit","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.CryptoSpec","page":"PeaceFounder.Model","title":"PeaceFounder.Model.CryptoSpec","text":"struct CryptoSpec\n hasher::Hash\n group::Spec\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_api/#PeaceFounder.Model.Digest","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.Generator","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.HMAC","page":"PeaceFounder.Model","title":"PeaceFounder.Model.HMAC","text":"struct HMAC\n key::Vector{UInt8}\n hasher::Hash\nend\n\nRepresent a hash message authetification code authorizer.\n\nInterface: hasher, digest, key\n\n\n\n\n\n","category":"type"},{"location":"model_api/#PeaceFounder.Model.Hash","page":"PeaceFounder.Model","title":"PeaceFounder.Model.Hash","text":"struct Hash\n spec::String\nend\n\nA specification for a hasher. See method digest.\n\n\n\n\n\n","category":"type"},{"location":"model_api/#PeaceFounder.Model.Pseudonym","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.Seal","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.Signer","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#HistoryTrees.leaf-Tuple{PeaceFounder.Model.AckInclusion}","page":"PeaceFounder.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_api/#HistoryTrees.root-Tuple{PeaceFounder.Model.AckConsistency}","page":"PeaceFounder.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_api/#HistoryTrees.root-Tuple{PeaceFounder.Model.Commit}","page":"PeaceFounder.Model","title":"HistoryTrees.root","text":"root(x)::Digest\n\nReturn a ledger root hash.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.commit-Tuple{PeaceFounder.Model.AckInclusion}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.commit","text":"commit(x)\n\nAccess a commit of an object x. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.digest-Tuple{Any, PeaceFounder.Model.CryptoSpec}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.digest","text":"digest(message::Vector{UInt8}, hasher::Hash)::Digest\ndigest(document, spec) = digest(canonicalize(message)::Vector{UInt8}, hasher(spec)::Hash)\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_api/#PeaceFounder.Model.digest-Tuple{Vector{UInt8}, PeaceFounder.Model.Hash}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.digest","text":"digest(bytes::Vector{UInt8}, hasher::Hash)::Digest\ndigest(x, spec) = digest(canonicalize(x)::Vector{UInt8}, hasher(spec)::Hash)\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_api/#PeaceFounder.Model.generate-Tuple{Type{PeaceFounder.Model.Signer}, PeaceFounder.Model.CryptoSpec}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.generator-Tuple{PeaceFounder.Model.CryptoSpec}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.generator","text":"generator(crypto::CryptoSpec)::Generator\n\nReturn a generator of the specification. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.generator-Tuple{Union{CryptoGroups.Specs.ECP, CryptoGroups.Specs.EC2N, CryptoGroups.Specs.Koblitz}}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.generator","text":"generator(spec::Spec)::Generator\n\nReturn a generator of spec.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.hasher-Tuple{PeaceFounder.Model.HMAC}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.hasher","text":"hasher(spec)::Hash\n\nAccess a hasher function from a given specification.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.index-Tuple{PeaceFounder.Model.AckConsistency}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.index-Tuple{PeaceFounder.Model.AckInclusion}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.index-Tuple{PeaceFounder.Model.Commit}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.index","text":"index(x)::Int\n\nReturn an index of a ledger state.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.isbinding-Tuple{Any, Any, PeaceFounder.Model.Hash}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.isbinding","text":"isbinding(x, y, spec::Hash)::Bool\nisbinding(x, y, spec) = isbinding(x, y, hasher(spec)::Hash)\n\nCheck binding of two objects x and y. Some general examples:\n\nCheck that a document is bound to it's signature. \nCheck that a record is included in the ledger.\nCheck that a given object is consistent with a ledger.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.issuer-Tuple{PeaceFounder.Model.Commit}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.key-Tuple{PeaceFounder.Model.HMAC}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.key","text":"key(x)\n\nAccess a secret key of an object x.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.seal-Tuple{Vector{UInt8}, PeaceFounder.Model.Signer}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.sign-Tuple{PeaceFounder.Model.Digest, PeaceFounder.Model.Generator, PeaceFounder.Model.Signer}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.sign-Tuple{Vector{UInt8}, PeaceFounder.Model.Generator, PeaceFounder.Model.Signer}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.state-Tuple{PeaceFounder.Model.Commit}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.canonicalize","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/","page":"PeaceFounder.Model","title":"PeaceFounder.Model","text":"PeaceFounder.Model.pseudonym","category":"page"},{"location":"model_api/#PeaceFounder.Model.pseudonym","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/","page":"PeaceFounder.Model","title":"PeaceFounder.Model","text":"PeaceFounder.Model.id","category":"page"},{"location":"model_api/#PeaceFounder.Model.id","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/","page":"PeaceFounder.Model","title":"PeaceFounder.Model","text":"PeaceFounder.Model.verify","category":"page"},{"location":"model_api/#PeaceFounder.Model.verify","page":"PeaceFounder.Model","title":"PeaceFounder.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::BraidWork, 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_api/#Admission","page":"PeaceFounder.Model","title":"Admission","text":"","category":"section"},{"location":"model_api/","page":"PeaceFounder.Model","title":"PeaceFounder.Model","text":"Modules = [PeaceFounder.Model]\nOrder = [:type, :function]\nPages = [\"Model/admissions.jl\"]","category":"page"},{"location":"model_api/#PeaceFounder.Model.Admission","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.Ticket","page":"PeaceFounder.Model","title":"PeaceFounder.Model.Ticket","text":"mutable struct Ticket\n const ticketid::TicketID\n timestamp::DateTime\n salt::Vector{UInt8}\n auth_code::Digest\n token::Digest\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 recruiter client in authorization system of choice, for instance, Recruiters.jl; salt contains a random bytestring generated by the server from which the reccruiter client can derive a token as token(ticketid, salt, hmac). auth_code is a server generated authetification code for a given salt and current metadata. Lastly admission contains a certified member pseudonym which was authetificated by the user with token.\n\n\n\n\n\n","category":"type"},{"location":"model_api/#PeaceFounder.Model.TicketID","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.TicketStatus","page":"PeaceFounder.Model","title":"PeaceFounder.Model.TicketStatus","text":"struct TicketStatus ticketid::TicketID timestamp::DateTime admission::Union{Nothing, Admission} end\n\nRepresents a public state of a ticket. See ticket_status and isadmitted methods. \n\n\n\n\n\n","category":"type"},{"location":"model_api/#PeaceFounder.Model.TokenRecruiter","page":"PeaceFounder.Model","title":"PeaceFounder.Model.TokenRecruiter","text":"struct TokenRecruiter\n metadata::Ref{Vector{UInt8}} \n tickets::Vector{Ticket}\n signer::Signer\n hmac::HMAC\nend\n\nRepresents a state for token recruiter 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(TokenRecruiter, 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, set_metadata!, enlist!, admit!, isadmitted, ticket_status\n\n\n\n\n\n","category":"type"},{"location":"model_api/#Base.in-Tuple{PeaceFounder.Model.TicketID, PeaceFounder.Model.TokenRecruiter}","page":"PeaceFounder.Model","title":"Base.in","text":"in(ticketid::TicketID, recruiter::TokenRecruiter)::Bool\n\nReturn true if there already is a ticket with ticketid.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.admit!-Tuple{PeaceFounder.Model.TokenRecruiter, PeaceFounder.Model.Pseudonym, PeaceFounder.Model.TicketID, PeaceFounder.Model.Digest}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.admit!","text":"admit!(recruiter::TokenRecruiter, id::Pseudonym, ticketid::TicketID, auth_code::Digest)::Admission\n\nAttempt to admit an identity pseudonym id for ticket ticketid with provided authorization code. This function retrieves a ticket with given ticketid and uses it's recorded token to check whether the request is binding. In the case of success an admnission certificate is formed with provided indenty pseudonym id and is signed by the recruter's private key. Otherwise when either of checks fail an error is raised. In the case ticket is already addmitted, returns previously stored admission. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.approve-Tuple{PeaceFounder.Model.Admission, PeaceFounder.Model.Signer}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.auth-Tuple{PeaceFounder.Model.Pseudonym, PeaceFounder.Model.HMAC}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.auth","text":"auth(id::Pseudonym, hmac::HMAC)::Digest\nauth(id::Pseudonym, token::Digest, hasher::Hash) = auth(id, HMAC(bytes(token), hasher))\n\nCompute a hash authorization code for identity pseudonym using token as a key. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.auth-Tuple{PeaceFounder.Model.TicketID, Dates.DateTime, PeaceFounder.Model.HMAC}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.auth","text":"auth(ticketid::TicketID, time::DateTime, hmac::HMAC)::Digest\n\nCompute a hash authorization code for ticketid at given time. The message needs to reach token recruiter within a 60 second window before it is obseleted.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.auth-Tuple{Vector{UInt8}, PeaceFounder.Model.TicketID, Vector{UInt8}, PeaceFounder.Model.HMAC}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.auth","text":"auth(metadata::Vector{UInt8}, ticketid::TicketID, salt::Vector{UInt8}, hmac::HMAC)::Digest\n\nCompute a hash authorization code for a metadata, salt from which a token is derived. Metadata can be configured to contain most recent server specification DemeSpec; ticketid takes session identifier role.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.enlist!-Tuple{PeaceFounder.Model.TokenRecruiter, PeaceFounder.Model.TicketID, Dates.DateTime, PeaceFounder.Model.Digest}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.enlist!","text":"enlist!(recruiter::TokenRecruiter, ticketid::TicketID, timestamp::DateTime, ticket_auth_code::Digest)::Tuple{Vector{UInt8}, Vector{UInt8}, Digest}\n\nAttempt to enlist a ticket with given ticketid authetificated by a recruit client at timestmap. This function checks the age of the request which need to be less than 60 seconds to be considered. Then the hash authorization code is checked after which a triplet of metadata, salt and reply_auth_code is returned. If either of theses checks fail an error is raised and needs to be dealt by the user. See a token method on how the token is derived.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.generate-Tuple{Type{PeaceFounder.Model.TokenRecruiter}, PeaceFounder.Model.CryptoSpec}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.generate","text":"generate(TokenRecruiter, spec::CryptoSpec)\n\nGenerate a new token recruiter with unique signer and athorization key.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.hmac-Tuple{PeaceFounder.Model.TokenRecruiter}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.hmac","text":"hmac(x)::HMAC\n\nReturn HMAC authorizer from a given object.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.isadmitted-Tuple{PeaceFounder.Model.TicketID, PeaceFounder.Model.TokenRecruiter}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.isadmitted","text":"isadmitted(ticketid::TicketID, recruiter::TokenRecruiter)\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":"model_api/#PeaceFounder.Model.isadmitted-Tuple{PeaceFounder.Model.TicketStatus}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.isadmitted","text":"isadmitted(status::TicketStatus)\n\nCheck whether ticket is addmitted. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.isbinding-Tuple{PeaceFounder.Model.Pseudonym, PeaceFounder.Model.Digest, PeaceFounder.Model.Digest, PeaceFounder.Model.Hash}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.isbinding","text":"isbinding(id::Pseudonym, auth_code::Digest, token::Digest, hasher::Hash)\n\nCheck whether a request for a new identity pseudonym admission is authetificated. The token is delivered to a user by recruit client.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.isbinding-Tuple{PeaceFounder.Model.TicketID, Dates.DateTime, PeaceFounder.Model.Digest, PeaceFounder.Model.HMAC}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.isbinding","text":"isbinding(ticketid::TicketID, timestamp::DateTime, auth_code::Digest, hmac::HMAC)\n\nCheck whether request for a new ticketid is authorized by recruit client. Note that freshness of the request is not considered within this method.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.isbinding-Tuple{Vector{UInt8}, PeaceFounder.Model.TicketID, Vector{UInt8}, PeaceFounder.Model.Digest, PeaceFounder.Model.HMAC}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.isbinding","text":"isbinding(metadata::Vector{UInt8}, ticketid::TicketID, salt::Vector{UInt8}, auth_code::Digest, hmac::HMAC)\n\nCheck whether a reply for a new ticketid is authorized by the recruit server. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.select-Tuple{Type{PeaceFounder.Model.Admission}, PeaceFounder.Model.Pseudonym, PeaceFounder.Model.TokenRecruiter}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.select","text":"select(Admission, ticketid::TicketID, recruiter::TokenRecruiter)::Union{Admission, Nothing}\n\nReturn admission for a ticket with given a given identity pseudonym from recruiter. 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":"model_api/#PeaceFounder.Model.select-Tuple{Type{PeaceFounder.Model.Admission}, PeaceFounder.Model.TicketID, PeaceFounder.Model.TokenRecruiter}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.select","text":"select(Admission, ticketid::TicketID, recruiter::TokenRecruiter)::Union{Admission, Nothing}\n\nReturn admission for a ticket with given ticketid from recruiter. 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":"model_api/#PeaceFounder.Model.select-Tuple{Type{PeaceFounder.Model.Ticket}, Function, PeaceFounder.Model.TokenRecruiter}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.select","text":"select(T, predicate::Function, recruiter::TokenRecruiter)::Union{T, Nothing}\n\nFrom a list of all recruiter 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":"model_api/#PeaceFounder.Model.set_metadata!-Tuple{PeaceFounder.Model.TokenRecruiter, Vector{UInt8}}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.set_metadata!","text":"set_metadata!(recruiter::TokenRecruiter, metadata::Vector{UInt8})\n\nReplace metadata for a recruiter. Note when data is replaced all unfinalized tokens need to be flushed. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.ticket-Tuple{PeaceFounder.Model.Admission}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.ticket","text":"ticket(x::Admission)\n\nReturn a TicketID which is admitted.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.ticket_status-Tuple{PeaceFounder.Model.TicketID, PeaceFounder.Model.TokenRecruiter}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.ticket_status","text":"ticket_status(ticketid::TicketID, recruiter::TokenRecruiter)::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":"model_api/#PeaceFounder.Model.tickets-Tuple{PeaceFounder.Model.TokenRecruiter}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.tickets","text":"tickets(recruiter::TokenRecruiter)::Vector{TicketID}\n\nReturn a list of registered ticket ids. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.token-Tuple{PeaceFounder.Model.TicketID, Vector{UInt8}, PeaceFounder.Model.HMAC}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.token","text":"token(ticketid::TicketID, salt::Vector{UInt8}, hmac::HMAC)\n\nCompute a recruit token for a given ticket with provided salt. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#BraidChain","page":"PeaceFounder.Model","title":"BraidChain","text":"","category":"section"},{"location":"model_api/","page":"PeaceFounder.Model","title":"PeaceFounder.Model","text":"Modules = [PeaceFounder.Model]\nOrder = [:type, :function]\nPages = [\"Model/braidchains.jl\", \"Model/braids.jl\"]","category":"page"},{"location":"model_api/#PeaceFounder.Model.BraidChain","page":"PeaceFounder.Model","title":"PeaceFounder.Model.BraidChain","text":"struct BraidChain\n members::Set{Pseudonym}\n ledger::Vector{Transaction}\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":"model_api/#PeaceFounder.Model.ChainState","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.DemeSpec","page":"PeaceFounder.Model","title":"PeaceFounder.Model.DemeSpec","text":"struct DemeSpec <: Transaction\n uuid::UUID\n title::String\n crypto::CryptoSpec\n guardian::Pseudonym\n recorder::Pseudonym\n recruiter::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};\nrecruiter::Pseudonym an authorithy which has rights to authorize new admissions to the deme. See Admission and Member;\nbraider::Pseudonym an authorithy which can do a legitimate braid jobs for other demes. See BraidWork; \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_api/#PeaceFounder.Model.Member","page":"PeaceFounder.Model","title":"PeaceFounder.Model.Member","text":"struct Member <: 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_api/#PeaceFounder.Model.Transaction","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#Base.push!-Tuple{PeaceFounder.Model.BraidChain, PeaceFounder.Model.Transaction}","page":"PeaceFounder.Model","title":"Base.push!","text":"push!(ledger::BraidChain, t::Transaction)\n\nAdd an element to the BraidChain 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":"model_api/#HistoryTrees.leaf-Tuple{PeaceFounder.Model.BraidChain, Int64}","page":"PeaceFounder.Model","title":"HistoryTrees.leaf","text":"leaf(ledger::BraidChain, N::Int)::Digest\n\nReturn a ledger's element digest at given index.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#HistoryTrees.root-Tuple{PeaceFounder.Model.BraidChain}","page":"PeaceFounder.Model","title":"HistoryTrees.root","text":"root(ledger::BraidChain[, 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":"model_api/#PeaceFounder.Model.ack_leaf-Tuple{PeaceFounder.Model.BraidChain, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.ack_leaf","text":"ack_leaf(ledger::BraidChain, 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":"model_api/#PeaceFounder.Model.ack_root-Tuple{PeaceFounder.Model.BraidChain, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.ack_root","text":"ack_root(ledger::BraidChain, 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":"model_api/#PeaceFounder.Model.approve-Tuple{PeaceFounder.Model.Member, PeaceFounder.Model.Signer}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.approve","text":"approve(member::Member, signer::Signer)::Member\n\nSign a member certificate and return it with approval field filled.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.commit!-Tuple{PeaceFounder.Model.BraidChain, PeaceFounder.Model.Signer}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.commit!","text":"commit!(ledger::BraidChain, 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":"model_api/#PeaceFounder.Model.commit-Tuple{PeaceFounder.Model.BraidChain}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.commit","text":"commit(ledger::BraidChain)\n\nReturn a current commit for a braichain. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.constituents-Tuple{PeaceFounder.Model.BraidChain}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.constituents","text":"constituents(ledger::BraidChain)::Set{Pseudonym}\n\nReturn all member identity pseudonyms. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.generator-Tuple{PeaceFounder.Model.BraidChain, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.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":"model_api/#PeaceFounder.Model.generator-Tuple{PeaceFounder.Model.BraidChain}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.generator","text":"generator(ledger::BraidChain)\n\nReturn a current relative generator for a braidchain ledger.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.generator-Tuple{PeaceFounder.Model.Member}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.generator","text":"generator(member::Member)::Generator\n\nGenerator at which member tries to roll in the braidchain.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.id-Tuple{PeaceFounder.Model.Member}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.id","text":"id(member::Member)::Pseudonym\n\nIdentity pseudonym for a member. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.isbinding-Tuple{PeaceFounder.Model.Admission, PeaceFounder.Model.DemeSpec}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.isbinding","text":"isbinding(admission::Admission, spec::DemeSpec)\n\nCheck whether issuer of admission is a recruiter set in spec.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.isbinding-Tuple{PeaceFounder.Model.Transaction, PeaceFounder.Model.AckInclusion{PeaceFounder.Model.ChainState}, PeaceFounder.Model.CryptoSpec}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.issuer-Tuple{PeaceFounder.Model.Member}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.issuer","text":"issuer(member::Member)::Pseudonym\n\nThe identiy of registrar who signed admission.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.list-Union{Tuple{T}, Tuple{Type{T}, PeaceFounder.Model.BraidChain}} where T<:PeaceFounder.Model.Transaction","page":"PeaceFounder.Model","title":"PeaceFounder.Model.list","text":"list(T, ledger::BraidChain)::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":"model_api/#PeaceFounder.Model.members-Tuple{PeaceFounder.Model.BraidChain, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.members","text":"members(ledger::BraidChain[, 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_api/#PeaceFounder.Model.pseudonym-Tuple{PeaceFounder.Model.Member}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.pseudonym","text":"pseudonym(member::Member)::Pseudonym\n\nPseudonym for a member at the generator(member). \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.reset_tree!-Tuple{PeaceFounder.Model.BraidChain}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.reset_tree!","text":"reset_tree!(ledger::BraidChain)\n\nRecompute a chain tree hash. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.roll-Tuple{PeaceFounder.Model.BraidChain}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.roll","text":"roll(ledger::BraidChain)::Vector{Member}\n\nReturn all member certificates from a braidchain ledger.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.select-Union{Tuple{T}, Tuple{Type{T}, Function, PeaceFounder.Model.BraidChain}} where T<:PeaceFounder.Model.Transaction","page":"PeaceFounder.Model","title":"PeaceFounder.Model.select","text":"select(T, predicate::Function, ledger::BraidChain)::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":"model_api/#PeaceFounder.Model.state-Tuple{PeaceFounder.Model.BraidChain}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.state","text":"state(ledger::BraidChain)\n\nReturn a current braidchain ledger state metadata.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.ticket-Tuple{PeaceFounder.Model.Member}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.ticket","text":"ticket(member::Member)\n\nTicket for a member admission certificate.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.BraidWork","page":"PeaceFounder.Model","title":"PeaceFounder.Model.BraidWork","text":"struct BraidWork <: Transaction\n braid::Simulator\n consumer::DemeSpec\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; consumer denotes a deme for which the braid is intended and 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_api/#PeaceFounder.Model.approve-Tuple{PeaceFounder.Model.BraidWork, PeaceFounder.Model.Signer}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.approve","text":"approve(braid::BraidWork, 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_api/#PeaceFounder.Model.braid-Tuple{PeaceFounder.Model.Generator, Union{Set{PeaceFounder.Model.Pseudonym}, Vector{PeaceFounder.Model.Pseudonym}}, PeaceFounder.Model.DemeSpec, PeaceFounder.Model.DemeSpec}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.input_generator-Tuple{PeaceFounder.Model.BraidWork}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.input_generator","text":"input_generator(braid::BraidWork)\n\nReturn input generator of the braid.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.input_members-Tuple{PeaceFounder.Model.BraidWork}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.input_members","text":"input_members(braid::BraidWork)\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_api/#PeaceFounder.Model.output_generator-Tuple{PeaceFounder.Model.BraidWork}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.output_generator","text":"output_generator(braid::BraidWork)\n\nReturn output genertor of the braid.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.output_members-Tuple{PeaceFounder.Model.BraidWork}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.output_members","text":"output_members(braid::BraidWork)\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_api/#PeaceFounder.Model.verify-Tuple{PeaceFounder.Model.BraidWork, PeaceFounder.Model.CryptoSpec}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.verify","text":"verify(braid::BraidWork, 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_api/#Ballot-Box","page":"PeaceFounder.Model","title":"Ballot Box","text":"","category":"section"},{"location":"model_api/","page":"PeaceFounder.Model","title":"PeaceFounder.Model","text":"Modules = [PeaceFounder.Model]\nOrder = [:type, :function]\nPages = [\"Model/proposals.jl\"]","category":"page"},{"location":"model_api/#PeaceFounder.Model.Ballot","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.BallotBox","page":"PeaceFounder.Model","title":"PeaceFounder.Model.BallotBox","text":"mutable struct BallotBox\n proposal::Proposal\n voters::Set{Pseudonym} # better than members\n collector::Pseudonym\n seed::Union{Digest, Nothing}\n crypto::CryptoSpec # on the other hand the inclusion of a vote should be binding enough as it includes proposal hash.\n queue::Vector{Vote}\n ledger::Vector{CastRecord}\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, members, ledger, spine, index, seed, leaf, root, record, 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":"model_api/#PeaceFounder.Model.BallotBoxState","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.CastAck","page":"PeaceFounder.Model","title":"PeaceFounder.Model.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_api/#PeaceFounder.Model.CastReceipt","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.CastRecord","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.PollingStation","page":"PeaceFounder.Model","title":"PeaceFounder.Model.PollingStation","text":"struct PollingStation\n halls::Vector{BallotBox}\n crypto::CryptoSpec\nend\n\nRepresents a pooling station which hosts ballotbox ledgers for every proposal collector manages. \n\nInterface: add!, ballotbox, record!, commit!, commit, ack_leaf, ack_root, ack_cast, record, receipt, spine, ledger, tally, set_seed!\n\n\n\n\n\n","category":"type"},{"location":"model_api/#PeaceFounder.Model.Proposal","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.Selection","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.Tally","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.Vote","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#Base.length-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"Base.length","text":"length(ledger::BallotBox)\n\nReturn a total length of the ledger including uncommited records in the queue.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#Base.push!-Tuple{PeaceFounder.Model.BallotBox, PeaceFounder.Model.CastRecord}","page":"PeaceFounder.Model","title":"Base.push!","text":"push!(ledger::BallotBox, 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":"model_api/#HistoryTrees.leaf-Tuple{PeaceFounder.Model.BallotBox, Int64}","page":"PeaceFounder.Model","title":"HistoryTrees.leaf","text":"leaf(ledger::BallotBox, N::Int)::Digest\n\nReturn a record digest used to form a history tree.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#HistoryTrees.root-Tuple{PeaceFounder.Model.BallotBox, Int64}","page":"PeaceFounder.Model","title":"HistoryTrees.root","text":"root(ledger::BallotBox[, 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":"model_api/#HistoryTrees.root-Tuple{PeaceFounder.Model.BallotBoxState}","page":"PeaceFounder.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_api/#PeaceFounder.Model.ack_cast-Tuple{PeaceFounder.Model.BallotBox, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.ack_cast","text":"ack_cast(ledger::BallotBox, index::Int)::CastAck\n\nCompute an acknowledgment for record inclusion at index.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.ack_cast-Tuple{PeaceFounder.Model.PollingStation, Base.UUID, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.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":"model_api/#PeaceFounder.Model.ack_leaf-Tuple{PeaceFounder.Model.BallotBox, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.ack_leaf","text":"ack_leaf(ledger::BallotBox, index::Int)::AckInclusion\n\nCompute an inclusion proof ::AckInclusion for record element at given index.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.ack_leaf-Tuple{PeaceFounder.Model.PollingStation, Base.UUID, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.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":"model_api/#PeaceFounder.Model.ack_root-Tuple{PeaceFounder.Model.BallotBox, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.ack_root","text":"ack_root(ledger::BallotBox, index::Int)::AckConsistency\n\nCompute a history tree consistency proof at index. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.ack_root-Tuple{PeaceFounder.Model.PollingStation, Base.UUID, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.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":"model_api/#PeaceFounder.Model.add!-Tuple{PeaceFounder.Model.PollingStation, PeaceFounder.Model.Proposal, Set{PeaceFounder.Model.Pseudonym}, PeaceFounder.Model.Pseudonym}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.add!","text":"add!(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":"model_api/#PeaceFounder.Model.ballotbox-Tuple{PeaceFounder.Model.PollingStation, Base.UUID}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.ballotbox","text":"ballotbox(station::PollingStation, uuid::UUID)::BallotBox\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":"model_api/#PeaceFounder.Model.ballotbox-Tuple{PeaceFounder.Model.PollingStation, PeaceFounder.Model.Digest}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.ballotbox","text":"ballotbox(station::PollingStation, proposal::Digest)::BallotBox\n\nReturn a ballotbox which has proposal with provided digest.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.commit!-Tuple{PeaceFounder.Model.BallotBox, Dates.DateTime, PeaceFounder.Model.Signer}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.commit!","text":"commit!(ledger::BallotBox[, 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":"model_api/#PeaceFounder.Model.commit!-Tuple{PeaceFounder.Model.PollingStation, Base.UUID, PeaceFounder.Model.Signer}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.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":"model_api/#PeaceFounder.Model.commit-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.commit","text":"commit(ledger::BallotBox)\n\nReturn a commit for the ballotbox ledger.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.commit-Tuple{PeaceFounder.Model.CastAck}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.commit","text":"commit(ack::CastAck)\n\nReturn a commit from a CastAck.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.commit-Tuple{PeaceFounder.Model.PollingStation, Base.UUID}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.commit","text":"commit(station::PollingStation, uuid::UUID)::Commit\n\nReturn a ballotbox commit.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.commit_index-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.commit_index","text":"commit_index(ledger::BallotBox)::Union{Index, Nothing}\n\nIndex at which commit is issued. See also length and index\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.commit_state-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.commit_state","text":"commit_state(ledger::BallotBox)\n\nReturn a committed state for a ballotbox ledger.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.generator-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.generator","text":"generator(ledger::BallotBox)\n\nReturn a relative generator which members use to sign votes anchored by the proposal.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.generator-Tuple{PeaceFounder.Model.Proposal}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.index-Tuple{PeaceFounder.Model.BallotBoxState}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.index-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.index","text":"index(ledger::BallotBox)\n\nReturn the current index of the ledger. See also length.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.isbinding-Tuple{PeaceFounder.Model.BraidChain, PeaceFounder.Model.ChainState}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.isbinding","text":"isbinding(chain::BraidChain, state::ChainState)::Bool\n\nCheck that chain state is consistent with braidchain ledger.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.isbinding-Tuple{PeaceFounder.Model.CastAck, PeaceFounder.Model.Proposal, PeaceFounder.Model.Hash}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.isbinding","text":"isbinding(ack::CastAck, proposal::Proposal, hasher::Hash)::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_api/#PeaceFounder.Model.isbinding-Tuple{PeaceFounder.Model.CastReceipt, PeaceFounder.Model.AckInclusion, PeaceFounder.Model.Hash}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.isbinding","text":"isbinding(receipt::CastReceipt, ack::AckInclusion, hasher::Hash)::Bool\n\nCheck that cast receipt is binding to received inclusion acknowledgment.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.isbinding-Tuple{PeaceFounder.Model.CastReceipt, PeaceFounder.Model.Vote, PeaceFounder.Model.Hash}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.isbinding","text":"isbinding(receipt::CastReceipt, vote::Vote, hasher::Hash)::Bool\n\nCheck that the receipt is bidning to a vote. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.isbinding-Tuple{PeaceFounder.Model.Vote, PeaceFounder.Model.CastAck, PeaceFounder.Model.CryptoSpec}","page":"PeaceFounder.Model","title":"PeaceFounder.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":"model_api/#PeaceFounder.Model.isbinding-Tuple{PeaceFounder.Model.Vote, PeaceFounder.Model.Proposal, PeaceFounder.Model.CryptoSpec}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.isbinding","text":"isbinding(vote::Vote, proposal::Proposal, crypto::CryptoSpec)\n\nCheck that the vote is bound to a proposal.. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.isconsistent-Tuple{PeaceFounder.Model.Selection, PeaceFounder.Model.Ballot}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.issuer-Tuple{PeaceFounder.Model.Proposal}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.issuer","text":"issuer(proposal::Proposal)\n\nIssuer of approval for the proposal.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.ledger-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.ledger","text":"ledger(ballotbox::BallotBox)::Vector{CastRecord}\n\nReturn all records from a ballotbox ledger.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.ledger-Tuple{PeaceFounder.Model.PollingStation, Base.UUID}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.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":"model_api/#PeaceFounder.Model.members-Tuple{Any}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.members","text":"members(ledger::BallotBox)\n\nReturn a list of member pseudonyms with which members authetificate their votes.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.pseudonym-Tuple{PeaceFounder.Model.Vote}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.receipt-Tuple{PeaceFounder.Model.BallotBox, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.receipt","text":"receipt(ledger::BallotBox, index::Int)::CastReceipt\n\nReturn a receipt for a ledger element.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.receipt-Tuple{PeaceFounder.Model.CastRecord, PeaceFounder.Model.Hash}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.receipt","text":"receipt(record::CastRecord, hasher::Hash)::CastReceipt\n\nConstruct a CastReceipt from a CastRecord with a provided hasher function.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.receipt-Tuple{PeaceFounder.Model.PollingStation, Base.UUID, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.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":"model_api/#PeaceFounder.Model.record!-Tuple{PeaceFounder.Model.BallotBox, PeaceFounder.Model.CastRecord}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.record!","text":"record!(ledger::BallotBox, 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":"model_api/#PeaceFounder.Model.record!-Tuple{PeaceFounder.Model.BallotBox, PeaceFounder.Model.Vote}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.record!","text":"record!(ledger::BallotBox, 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":"model_api/#PeaceFounder.Model.record!-Tuple{PeaceFounder.Model.PollingStation, Base.UUID, PeaceFounder.Model.Vote}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.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":"model_api/#PeaceFounder.Model.record!-Tuple{PeaceFounder.Model.PollingStation, PeaceFounder.Model.Vote}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.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":"model_api/#PeaceFounder.Model.record-Tuple{PeaceFounder.Model.BallotBox, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.record","text":"record(ledger::BallotBox, index::Int)::CastRecord\n\nReturn a ledger record at provided index.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.record-Tuple{PeaceFounder.Model.PollingStation, Base.UUID, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.record","text":"record(station::PollingStation, uuid::UUID, N::Int)::CastRecord\n\nReturn a record with an index N at ballotbox with uuid.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.reset_tree!-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.reset_tree!","text":"reset_tree!(ledger::BallotBox)\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":"model_api/#PeaceFounder.Model.seed-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.seed","text":"seed(ledger::BallotBox)::Union{Digest, Nothing}\n\nReturn a random selected seed used in the voting.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.set_seed!-Tuple{PeaceFounder.Model.BallotBox, PeaceFounder.Model.Digest}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.set_seed!","text":"set_seed!(ledger::BallotBox, seed::Digest)\n\nSet's a seed of the ballotbox.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.set_seed!-Tuple{PeaceFounder.Model.PollingStation, Base.UUID, PeaceFounder.Model.Digest}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.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":"model_api/#PeaceFounder.Model.spine-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.spine","text":"spine(ledger::BallotBox)::Vector{Digest}\n\nReturn a history tree leaf vector.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.spine-Tuple{PeaceFounder.Model.PollingStation, Base.UUID}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.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":"model_api/#PeaceFounder.Model.state-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.state","text":"state(ledger::BallotBox; with_tally::Union{Nothing, Bool} = nothing)::BallotBoxState\n\nReturn a state metadata for ballotbox ledger. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.state-Tuple{PeaceFounder.Model.Proposal}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.tally-Tuple{PeaceFounder.Model.Ballot, AbstractVector{PeaceFounder.Model.Selection}}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.tally-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.tally","text":"tally(ledger::BallotBox)\n\nCompute a tally for a ballotbox ledger. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.tally-Tuple{PeaceFounder.Model.PollingStation, Base.UUID}","page":"PeaceFounder.Model","title":"PeaceFounder.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":"model_api/#PeaceFounder.Model.uuid-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.uuid","text":"uuid(ledger::BallotBox)\n\nReturn a UUID of the proposal.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.uuid-Tuple{PeaceFounder.Model.Proposal}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.validate-Tuple{PeaceFounder.Model.BallotBox, PeaceFounder.Model.Vote}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.validate","text":"validate(ledger::BallotBox, 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":"model_api/#PeaceFounder.Model.verify-Tuple{PeaceFounder.Model.CastAck, PeaceFounder.Model.CryptoSpec}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.vote-Tuple{PeaceFounder.Model.Proposal, PeaceFounder.Model.Digest, PeaceFounder.Model.Selection, PeaceFounder.Model.Signer}","page":"PeaceFounder.Model","title":"PeaceFounder.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":"#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":"A major hurdle in mainstream E2E (end-to-end) e-voting system designs is a multiparty protocol ceremony coordination required for initiating a threshold decryption key and performing decryption at the end of the vote. The voter's anonymity demands independence of the involved parties, which introduces a risk of sabotage where election results could be left undecrypted and unannounced. Moreover, due to the need to encode ballot selection in a group element, only a limited number of ballot types can be supported and face challenges, for instance, for cardinal and budget planning ballots. This is even more restrictive when a homomorphic counting procedure is employed.","category":"page"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"An alternative approach is to anonymise voter's credentials instead of the votes. The idea has been explored with blind signature schemes, but auditing the authority's issuance of signatures and detecting key leaks remains unresolved. A subsequent method, proposed by Haenni \\& Spycher, leverages ElGamal re-encryption to verifiably exponentiate voters' public keys in tandem with a generator using zero-knowledge proofs. Together with a history tree bulletin board implementation, it forms the foundation for the design of the PeaceFounder voting system.","category":"page"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"The PeaceFounder voting system builds upon the foundational work of Haenni & Spycher, serving as a practical implementation of their proposal. Nevertheless, PeaceFounder introduces several key features:","category":"page"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"A scalable bulletin board design with thin-member clients ensuring the immutability of all published records without replication;\nA registration protocol for new members that catches them up with the current relative generator;\nMechanisms to handle uncooperative bulletin boards through auditors/proxies while preventing potential exploitation by coercers and bribers with time-restricted receipt freeness and revoting;\nA system allowing a member's device to detect private key leaks coming from spyware or bad cryptography via sequence numbers and bitmasks;\nA malware detection mechanism post-voting, where the device displayed receipt, is compared to a bulletin board while not being deceived into verifying another voter's vote.","category":"page"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"Furthermore, PeaceFounder demonstrates that a single maintainer can feasibly deploy the system. That is possible due to the lack of a multi-party ceremony and member device accountability of the bulletin board. It also offers seamless integration opportunities with existing infrastructure and political environment for supporting different ways proposals are put to the ballot box, and member authenticity is verified and later audited. Additionally, the PeaceFounder showcases user experience for the voter, minimising their exposure to complex byte strings while maintaining cryptographic soundness along with other usability improvements. ","category":"page"},{"location":"#Demo","page":"PeaceFounder.jl","title":"Demo","text":"","category":"section"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"For a demo, go to the PeaceFounderDemo repository. A 10-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":"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 for the votes specified in the DemeSpec fields.","category":"page"},{"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. This 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 would be 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":"
      \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":"client/#Client","page":"Client","title":"Client","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/","page":"Client","title":"Client","text":"In the future, a bundle will be available for every major system so that all voters can install the client without technical knowledge. ","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"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 the future versions of the client, which can be accelerated by letting me know if that interests you. ","category":"page"},{"location":"client/","page":"Client","title":"Client","text":"In future, the focus will be on the mobile application 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/#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, aka not being 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 prevents 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/#REST-API","page":"REST","title":"REST API","text":"","category":"section"},{"location":"schema/","page":"REST","title":"REST","text":"This is an approximate rest API for the PeaceFounder. In future, this will be properly generated and documented from the code. ","category":"page"},{"location":"schema/","page":"REST","title":"REST","text":"GET /deme # returns a current manifest file\nGET /deme/{hash}\n\nPOST /tickets : Tuple{TicketID, DateTime, auth_code::Digest} -> Tuple{salt::Vector{UInt8}, auth_code::Digest} # resets token when repeated\nDELETE /tickets/{TicketID}\nPUT /tickets/{TicketID} : Tuple{Pseudonym, auth_code::Digest} -> Admission\nGET /tickets/{TicketID} : TicketStatus\n\nPOST /braidchain/members : Member -> AckInclusion{ChainState}\nGET /braidchain/members : Vector{Tuple{Int, Member}}\nGET /braidchain/members?id={Pseudonym} : Tuple{Int, Member}\nGET /braidchain/members?pseudonym={Pseudonym} : Tuple{Int, Member}\n\nPOST /braidchain/proposals : Proposal -> AckInclusion\nGET /braidcahin/proposals/{UUID} : Tuple{Int, Proposal}\nGET /braidchain/proposals : Vector{Tuple{Int, Proposal}}\n\nGET /braidchain/{Int}/record : Transaction\nGET /braidchain/{Int}/leaf : AckInclusion{ChainState}\nGET /braidchain/{Int}/root : AckConsistency{ChainState}\nGET /braidchain/commit : Commit{ChainState}\nGET /braidchain/tar : BraidChainArchive\n\nPOST /pollingstation/{UUID}/votes : Vote -> CastAck\nGET /pollingstation/{UUID}/spine : Vector{Digest}\nGET /pollingstation/{UUID}/commit : Commit{BallotBoxState}\nGET /pollingstation/{UUID}/proposal : Tuple{Int, Proposal}\nGET /pollingstation/{UUID}/votes/{Int}/record : CastRecord\nGET /pollingstation/{UUID}/votes/{Int}/receipt : CastReceipt\nGET /pollingstation/{UUID}/votes/{Int}/leaf : AckInclusion{BallotBoxState}\nGET /pollingstation/{UUID}/votes/{Int}/root : AckConsistency{BallotBoxState}\nGET /pollingstation/{UUID}/tar : BallotBoxArchive\nGET /pollingstation/collectors # necessary to make a proposal","category":"page"},{"location":"schema/#Braider","page":"REST","title":"Braider","text":"","category":"section"},{"location":"schema/","page":"REST","title":"REST","text":"GET /braider : BraiderStatus\nGET /braider/jobs : Vector{JobID}\nGET /braider/jobs/{JobID} : JobStatus\nGET /braider/jobs/{JobID}/braid : Braid\nPOST /braider/jobs : BraidJobSpec -> JobID\nPUT /braider/jobs/{JobID} : Tuple{Vector{Pseudonym}, Generator} -> JobStatus","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. Currently, the best auditing strategy is to recreate the braidchain and ballotbox 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. Every voter, after elections, 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":"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":"audittools/#PeaceFounder.AuditTools","page":"PeaceFounder.AuditTools","title":"PeaceFounder.AuditTools","text":"","category":"section"},{"location":"audittools/","page":"PeaceFounder.AuditTools","title":"PeaceFounder.AuditTools","text":"PeaceFounder.AuditTools","category":"page"},{"location":"audittools/","page":"PeaceFounder.AuditTools","title":"PeaceFounder.AuditTools","text":"Modules = [PeaceFounder.AuditTools]\nOrder = [:module, :type, :function]","category":"page"},{"location":"audittools/#PeaceFounder.AuditTools","page":"PeaceFounder.AuditTools","title":"PeaceFounder.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.AuditTools.BallotBoxArchive","page":"PeaceFounder.AuditTools","title":"PeaceFounder.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.AuditTools.BraidChainArchive","page":"PeaceFounder.AuditTools","title":"PeaceFounder.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.AuditTools.archive","page":"PeaceFounder.AuditTools","title":"PeaceFounder.AuditTools.archive","text":"archive(ledger::BraidChain)::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.AuditTools.audit","page":"PeaceFounder.AuditTools","title":"PeaceFounder.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.AuditTools.audit_braids","page":"PeaceFounder.AuditTools","title":"PeaceFounder.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.AuditTools.audit_lots","page":"PeaceFounder.AuditTools","title":"PeaceFounder.AuditTools.audit_lots","text":"audit_lots(ledger::BraidChainArchive)\n\nCheck integrity correct nonce commitments. Note that it is possible that this will be moved out to a ballotbox ledger in the future. Also service like DRAND would be beneficial to reduce trust assumptions.\n\n\n\n\n\n","category":"function"},{"location":"audittools/#PeaceFounder.AuditTools.audit_members","page":"PeaceFounder.AuditTools","title":"PeaceFounder.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; - Member 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.AuditTools.audit_proposals","page":"PeaceFounder.AuditTools","title":"PeaceFounder.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.AuditTools.audit_roster","page":"PeaceFounder.AuditTools","title":"PeaceFounder.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.AuditTools.checksum","page":"PeaceFounder.AuditTools","title":"PeaceFounder.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":"overview/#Overview","page":"Overview","title":"Overview","text":"","category":"section"},{"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 ma","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/#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":"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":"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":"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/#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":"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":"model_api/#PeaceFounder.Model","page":"PeaceFounder.Model","title":"PeaceFounder.Model","text":"","category":"section"},{"location":"model_api/#Primitives","page":"PeaceFounder.Model","title":"Primitives","text":"","category":"section"},{"location":"model_api/","page":"PeaceFounder.Model","title":"PeaceFounder.Model","text":"Modules = [PeaceFounder.Model]\nOrder = [:type, :function]\nPages = [\"Model/crypto.jl\", \"Model/seal.jl\"]","category":"page"},{"location":"model_api/#PeaceFounder.Model.AckConsistency","page":"PeaceFounder.Model","title":"PeaceFounder.Model.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_api/#PeaceFounder.Model.AckInclusion","page":"PeaceFounder.Model","title":"PeaceFounder.Model.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_api/#PeaceFounder.Model.Commit","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.CryptoSpec","page":"PeaceFounder.Model","title":"PeaceFounder.Model.CryptoSpec","text":"struct CryptoSpec\n hasher::Hash\n group::Spec\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_api/#PeaceFounder.Model.Digest","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.Generator","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.HMAC","page":"PeaceFounder.Model","title":"PeaceFounder.Model.HMAC","text":"struct HMAC\n key::Vector{UInt8}\n hasher::Hash\nend\n\nRepresent a hash message authetification code authorizer.\n\nInterface: hasher, digest, key\n\n\n\n\n\n","category":"type"},{"location":"model_api/#PeaceFounder.Model.Hash","page":"PeaceFounder.Model","title":"PeaceFounder.Model.Hash","text":"struct Hash\n spec::String\nend\n\nA specification for a hasher. See method digest.\n\n\n\n\n\n","category":"type"},{"location":"model_api/#PeaceFounder.Model.Pseudonym","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.Seal","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.Signer","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#HistoryTrees.leaf-Tuple{PeaceFounder.Model.AckInclusion}","page":"PeaceFounder.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_api/#HistoryTrees.root-Tuple{PeaceFounder.Model.AckConsistency}","page":"PeaceFounder.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_api/#HistoryTrees.root-Tuple{PeaceFounder.Model.Commit}","page":"PeaceFounder.Model","title":"HistoryTrees.root","text":"root(x)::Digest\n\nReturn a ledger root hash.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.commit-Tuple{PeaceFounder.Model.AckInclusion}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.commit","text":"commit(x)\n\nAccess a commit of an object x. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.digest-Tuple{Any, PeaceFounder.Model.CryptoSpec}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.digest","text":"digest(message::Vector{UInt8}, hasher::Hash)::Digest\ndigest(document, spec) = digest(canonicalize(message)::Vector{UInt8}, hasher(spec)::Hash)\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_api/#PeaceFounder.Model.digest-Tuple{Vector{UInt8}, PeaceFounder.Model.Hash}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.digest","text":"digest(bytes::Vector{UInt8}, hasher::Hash)::Digest\ndigest(x, spec) = digest(canonicalize(x)::Vector{UInt8}, hasher(spec)::Hash)\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_api/#PeaceFounder.Model.generate-Tuple{Type{PeaceFounder.Model.Signer}, PeaceFounder.Model.CryptoSpec}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.generator-Tuple{PeaceFounder.Model.CryptoSpec}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.generator","text":"generator(crypto::CryptoSpec)::Generator\n\nReturn a generator of the specification. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.generator-Tuple{Union{CryptoGroups.Specs.ECP, CryptoGroups.Specs.EC2N, CryptoGroups.Specs.Koblitz}}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.generator","text":"generator(spec::Spec)::Generator\n\nReturn a generator of spec.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.hasher-Tuple{PeaceFounder.Model.HMAC}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.hasher","text":"hasher(spec)::Hash\n\nAccess a hasher function from a given specification.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.index-Tuple{PeaceFounder.Model.AckConsistency}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.index-Tuple{PeaceFounder.Model.AckInclusion}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.index-Tuple{PeaceFounder.Model.Commit}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.index","text":"index(x)::Int\n\nReturn an index of a ledger state.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.isbinding-Tuple{Any, Any, PeaceFounder.Model.Hash}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.isbinding","text":"isbinding(x, y, spec::Hash)::Bool\nisbinding(x, y, spec) = isbinding(x, y, hasher(spec)::Hash)\n\nCheck binding of two objects x and y. Some general examples:\n\nCheck that a document is bound to it's signature. \nCheck that a record is included in the ledger.\nCheck that a given object is consistent with a ledger.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.issuer-Tuple{PeaceFounder.Model.Commit}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.key-Tuple{PeaceFounder.Model.HMAC}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.key","text":"key(x)\n\nAccess a secret key of an object x.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.seal-Tuple{Vector{UInt8}, PeaceFounder.Model.Signer}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.sign-Tuple{PeaceFounder.Model.Digest, PeaceFounder.Model.Generator, PeaceFounder.Model.Signer}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.sign-Tuple{Vector{UInt8}, PeaceFounder.Model.Generator, PeaceFounder.Model.Signer}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.state-Tuple{PeaceFounder.Model.Commit}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.canonicalize","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/","page":"PeaceFounder.Model","title":"PeaceFounder.Model","text":"PeaceFounder.Model.pseudonym","category":"page"},{"location":"model_api/#PeaceFounder.Model.pseudonym","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/","page":"PeaceFounder.Model","title":"PeaceFounder.Model","text":"PeaceFounder.Model.id","category":"page"},{"location":"model_api/#PeaceFounder.Model.id","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/","page":"PeaceFounder.Model","title":"PeaceFounder.Model","text":"PeaceFounder.Model.verify","category":"page"},{"location":"model_api/#PeaceFounder.Model.verify","page":"PeaceFounder.Model","title":"PeaceFounder.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::BraidWork, 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_api/#Admission","page":"PeaceFounder.Model","title":"Admission","text":"","category":"section"},{"location":"model_api/","page":"PeaceFounder.Model","title":"PeaceFounder.Model","text":"Modules = [PeaceFounder.Model]\nOrder = [:type, :function]\nPages = [\"Model/admissions.jl\"]","category":"page"},{"location":"model_api/#PeaceFounder.Model.Admission","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.Ticket","page":"PeaceFounder.Model","title":"PeaceFounder.Model.Ticket","text":"mutable struct Ticket\n const ticketid::TicketID\n timestamp::DateTime\n salt::Vector{UInt8}\n auth_code::Digest\n token::Digest\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 recruiter client in authorization system of choice, for instance, Recruiters.jl; salt contains a random bytestring generated by the server from which the reccruiter client can derive a token as token(ticketid, salt, hmac). auth_code is a server generated authetification code for a given salt and current metadata. Lastly admission contains a certified member pseudonym which was authetificated by the user with token.\n\n\n\n\n\n","category":"type"},{"location":"model_api/#PeaceFounder.Model.TicketID","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.TicketStatus","page":"PeaceFounder.Model","title":"PeaceFounder.Model.TicketStatus","text":"struct TicketStatus ticketid::TicketID timestamp::DateTime admission::Union{Nothing, Admission} end\n\nRepresents a public state of a ticket. See ticket_status and isadmitted methods. \n\n\n\n\n\n","category":"type"},{"location":"model_api/#PeaceFounder.Model.TokenRecruiter","page":"PeaceFounder.Model","title":"PeaceFounder.Model.TokenRecruiter","text":"struct TokenRecruiter\n metadata::Ref{Vector{UInt8}} \n tickets::Vector{Ticket}\n signer::Signer\n hmac::HMAC\nend\n\nRepresents a state for token recruiter 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(TokenRecruiter, 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, set_metadata!, enlist!, admit!, isadmitted, ticket_status\n\n\n\n\n\n","category":"type"},{"location":"model_api/#Base.in-Tuple{PeaceFounder.Model.TicketID, PeaceFounder.Model.TokenRecruiter}","page":"PeaceFounder.Model","title":"Base.in","text":"in(ticketid::TicketID, recruiter::TokenRecruiter)::Bool\n\nReturn true if there already is a ticket with ticketid.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.admit!-Tuple{PeaceFounder.Model.TokenRecruiter, PeaceFounder.Model.Pseudonym, PeaceFounder.Model.TicketID, PeaceFounder.Model.Digest}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.admit!","text":"admit!(recruiter::TokenRecruiter, id::Pseudonym, ticketid::TicketID, auth_code::Digest)::Admission\n\nAttempt to admit an identity pseudonym id for ticket ticketid with provided authorization code. This function retrieves a ticket with given ticketid and uses it's recorded token to check whether the request is binding. In the case of success an admnission certificate is formed with provided indenty pseudonym id and is signed by the recruter's private key. Otherwise when either of checks fail an error is raised. In the case ticket is already addmitted, returns previously stored admission. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.approve-Tuple{PeaceFounder.Model.Admission, PeaceFounder.Model.Signer}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.auth-Tuple{PeaceFounder.Model.Pseudonym, PeaceFounder.Model.HMAC}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.auth","text":"auth(id::Pseudonym, hmac::HMAC)::Digest\nauth(id::Pseudonym, token::Digest, hasher::Hash) = auth(id, HMAC(bytes(token), hasher))\n\nCompute a hash authorization code for identity pseudonym using token as a key. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.auth-Tuple{PeaceFounder.Model.TicketID, Dates.DateTime, PeaceFounder.Model.HMAC}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.auth","text":"auth(ticketid::TicketID, time::DateTime, hmac::HMAC)::Digest\n\nCompute a hash authorization code for ticketid at given time. The message needs to reach token recruiter within a 60 second window before it is obseleted.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.auth-Tuple{Vector{UInt8}, PeaceFounder.Model.TicketID, Vector{UInt8}, PeaceFounder.Model.HMAC}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.auth","text":"auth(metadata::Vector{UInt8}, ticketid::TicketID, salt::Vector{UInt8}, hmac::HMAC)::Digest\n\nCompute a hash authorization code for a metadata, salt from which a token is derived. Metadata can be configured to contain most recent server specification DemeSpec; ticketid takes session identifier role.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.enlist!-Tuple{PeaceFounder.Model.TokenRecruiter, PeaceFounder.Model.TicketID, Dates.DateTime, PeaceFounder.Model.Digest}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.enlist!","text":"enlist!(recruiter::TokenRecruiter, ticketid::TicketID, timestamp::DateTime, ticket_auth_code::Digest)::Tuple{Vector{UInt8}, Vector{UInt8}, Digest}\n\nAttempt to enlist a ticket with given ticketid authetificated by a recruit client at timestmap. This function checks the age of the request which need to be less than 60 seconds to be considered. Then the hash authorization code is checked after which a triplet of metadata, salt and reply_auth_code is returned. If either of theses checks fail an error is raised and needs to be dealt by the user. See a token method on how the token is derived.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.generate-Tuple{Type{PeaceFounder.Model.TokenRecruiter}, PeaceFounder.Model.CryptoSpec}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.generate","text":"generate(TokenRecruiter, spec::CryptoSpec)\n\nGenerate a new token recruiter with unique signer and athorization key.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.hmac-Tuple{PeaceFounder.Model.TokenRecruiter}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.hmac","text":"hmac(x)::HMAC\n\nReturn HMAC authorizer from a given object.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.isadmitted-Tuple{PeaceFounder.Model.TicketID, PeaceFounder.Model.TokenRecruiter}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.isadmitted","text":"isadmitted(ticketid::TicketID, recruiter::TokenRecruiter)\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":"model_api/#PeaceFounder.Model.isadmitted-Tuple{PeaceFounder.Model.TicketStatus}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.isadmitted","text":"isadmitted(status::TicketStatus)\n\nCheck whether ticket is addmitted. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.isbinding-Tuple{PeaceFounder.Model.Pseudonym, PeaceFounder.Model.Digest, PeaceFounder.Model.Digest, PeaceFounder.Model.Hash}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.isbinding","text":"isbinding(id::Pseudonym, auth_code::Digest, token::Digest, hasher::Hash)\n\nCheck whether a request for a new identity pseudonym admission is authetificated. The token is delivered to a user by recruit client.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.isbinding-Tuple{PeaceFounder.Model.TicketID, Dates.DateTime, PeaceFounder.Model.Digest, PeaceFounder.Model.HMAC}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.isbinding","text":"isbinding(ticketid::TicketID, timestamp::DateTime, auth_code::Digest, hmac::HMAC)\n\nCheck whether request for a new ticketid is authorized by recruit client. Note that freshness of the request is not considered within this method.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.isbinding-Tuple{Vector{UInt8}, PeaceFounder.Model.TicketID, Vector{UInt8}, PeaceFounder.Model.Digest, PeaceFounder.Model.HMAC}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.isbinding","text":"isbinding(metadata::Vector{UInt8}, ticketid::TicketID, salt::Vector{UInt8}, auth_code::Digest, hmac::HMAC)\n\nCheck whether a reply for a new ticketid is authorized by the recruit server. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.select-Tuple{Type{PeaceFounder.Model.Admission}, PeaceFounder.Model.Pseudonym, PeaceFounder.Model.TokenRecruiter}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.select","text":"select(Admission, ticketid::TicketID, recruiter::TokenRecruiter)::Union{Admission, Nothing}\n\nReturn admission for a ticket with given a given identity pseudonym from recruiter. 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":"model_api/#PeaceFounder.Model.select-Tuple{Type{PeaceFounder.Model.Admission}, PeaceFounder.Model.TicketID, PeaceFounder.Model.TokenRecruiter}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.select","text":"select(Admission, ticketid::TicketID, recruiter::TokenRecruiter)::Union{Admission, Nothing}\n\nReturn admission for a ticket with given ticketid from recruiter. 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":"model_api/#PeaceFounder.Model.select-Tuple{Type{PeaceFounder.Model.Ticket}, Function, PeaceFounder.Model.TokenRecruiter}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.select","text":"select(T, predicate::Function, recruiter::TokenRecruiter)::Union{T, Nothing}\n\nFrom a list of all recruiter 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":"model_api/#PeaceFounder.Model.set_metadata!-Tuple{PeaceFounder.Model.TokenRecruiter, Vector{UInt8}}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.set_metadata!","text":"set_metadata!(recruiter::TokenRecruiter, metadata::Vector{UInt8})\n\nReplace metadata for a recruiter. Note when data is replaced all unfinalized tokens need to be flushed. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.ticket-Tuple{PeaceFounder.Model.Admission}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.ticket","text":"ticket(x::Admission)\n\nReturn a TicketID which is admitted.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.ticket_status-Tuple{PeaceFounder.Model.TicketID, PeaceFounder.Model.TokenRecruiter}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.ticket_status","text":"ticket_status(ticketid::TicketID, recruiter::TokenRecruiter)::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":"model_api/#PeaceFounder.Model.tickets-Tuple{PeaceFounder.Model.TokenRecruiter}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.tickets","text":"tickets(recruiter::TokenRecruiter)::Vector{TicketID}\n\nReturn a list of registered ticket ids. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.token-Tuple{PeaceFounder.Model.TicketID, Vector{UInt8}, PeaceFounder.Model.HMAC}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.token","text":"token(ticketid::TicketID, salt::Vector{UInt8}, hmac::HMAC)\n\nCompute a recruit token for a given ticket with provided salt. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#BraidChain","page":"PeaceFounder.Model","title":"BraidChain","text":"","category":"section"},{"location":"model_api/","page":"PeaceFounder.Model","title":"PeaceFounder.Model","text":"Modules = [PeaceFounder.Model]\nOrder = [:type, :function]\nPages = [\"Model/braidchains.jl\", \"Model/braids.jl\"]","category":"page"},{"location":"model_api/#PeaceFounder.Model.BraidChain","page":"PeaceFounder.Model","title":"PeaceFounder.Model.BraidChain","text":"struct BraidChain\n members::Set{Pseudonym}\n ledger::Vector{Transaction}\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":"model_api/#PeaceFounder.Model.ChainState","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.DemeSpec","page":"PeaceFounder.Model","title":"PeaceFounder.Model.DemeSpec","text":"struct DemeSpec <: Transaction\n uuid::UUID\n title::String\n crypto::CryptoSpec\n guardian::Pseudonym\n recorder::Pseudonym\n recruiter::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};\nrecruiter::Pseudonym an authorithy which has rights to authorize new admissions to the deme. See Admission and Member;\nbraider::Pseudonym an authorithy which can do a legitimate braid jobs for other demes. See BraidWork; \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_api/#PeaceFounder.Model.Member","page":"PeaceFounder.Model","title":"PeaceFounder.Model.Member","text":"struct Member <: 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_api/#PeaceFounder.Model.Transaction","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#Base.push!-Tuple{PeaceFounder.Model.BraidChain, PeaceFounder.Model.Transaction}","page":"PeaceFounder.Model","title":"Base.push!","text":"push!(ledger::BraidChain, t::Transaction)\n\nAdd an element to the BraidChain 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":"model_api/#HistoryTrees.leaf-Tuple{PeaceFounder.Model.BraidChain, Int64}","page":"PeaceFounder.Model","title":"HistoryTrees.leaf","text":"leaf(ledger::BraidChain, N::Int)::Digest\n\nReturn a ledger's element digest at given index.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#HistoryTrees.root-Tuple{PeaceFounder.Model.BraidChain}","page":"PeaceFounder.Model","title":"HistoryTrees.root","text":"root(ledger::BraidChain[, 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":"model_api/#PeaceFounder.Model.ack_leaf-Tuple{PeaceFounder.Model.BraidChain, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.ack_leaf","text":"ack_leaf(ledger::BraidChain, 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":"model_api/#PeaceFounder.Model.ack_root-Tuple{PeaceFounder.Model.BraidChain, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.ack_root","text":"ack_root(ledger::BraidChain, 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":"model_api/#PeaceFounder.Model.approve-Tuple{PeaceFounder.Model.Member, PeaceFounder.Model.Signer}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.approve","text":"approve(member::Member, signer::Signer)::Member\n\nSign a member certificate and return it with approval field filled.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.commit!-Tuple{PeaceFounder.Model.BraidChain, PeaceFounder.Model.Signer}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.commit!","text":"commit!(ledger::BraidChain, 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":"model_api/#PeaceFounder.Model.commit-Tuple{PeaceFounder.Model.BraidChain}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.commit","text":"commit(ledger::BraidChain)\n\nReturn a current commit for a braichain. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.constituents-Tuple{PeaceFounder.Model.BraidChain}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.constituents","text":"constituents(ledger::BraidChain)::Set{Pseudonym}\n\nReturn all member identity pseudonyms. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.generator-Tuple{PeaceFounder.Model.BraidChain, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.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":"model_api/#PeaceFounder.Model.generator-Tuple{PeaceFounder.Model.BraidChain}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.generator","text":"generator(ledger::BraidChain)\n\nReturn a current relative generator for a braidchain ledger.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.generator-Tuple{PeaceFounder.Model.Member}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.generator","text":"generator(member::Member)::Generator\n\nGenerator at which member tries to roll in the braidchain.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.id-Tuple{PeaceFounder.Model.Member}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.id","text":"id(member::Member)::Pseudonym\n\nIdentity pseudonym for a member. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.isbinding-Tuple{PeaceFounder.Model.Admission, PeaceFounder.Model.DemeSpec}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.isbinding","text":"isbinding(admission::Admission, spec::DemeSpec)\n\nCheck whether issuer of admission is a recruiter set in spec.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.isbinding-Tuple{PeaceFounder.Model.Transaction, PeaceFounder.Model.AckInclusion{PeaceFounder.Model.ChainState}, PeaceFounder.Model.CryptoSpec}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.issuer-Tuple{PeaceFounder.Model.Member}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.issuer","text":"issuer(member::Member)::Pseudonym\n\nThe identiy of registrar who signed admission.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.list-Union{Tuple{T}, Tuple{Type{T}, PeaceFounder.Model.BraidChain}} where T<:PeaceFounder.Model.Transaction","page":"PeaceFounder.Model","title":"PeaceFounder.Model.list","text":"list(T, ledger::BraidChain)::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":"model_api/#PeaceFounder.Model.members-Tuple{PeaceFounder.Model.BraidChain, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.members","text":"members(ledger::BraidChain[, 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_api/#PeaceFounder.Model.pseudonym-Tuple{PeaceFounder.Model.Member}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.pseudonym","text":"pseudonym(member::Member)::Pseudonym\n\nPseudonym for a member at the generator(member). \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.reset_tree!-Tuple{PeaceFounder.Model.BraidChain}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.reset_tree!","text":"reset_tree!(ledger::BraidChain)\n\nRecompute a chain tree hash. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.roll-Tuple{PeaceFounder.Model.BraidChain}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.roll","text":"roll(ledger::BraidChain)::Vector{Member}\n\nReturn all member certificates from a braidchain ledger.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.select-Union{Tuple{T}, Tuple{Type{T}, Function, PeaceFounder.Model.BraidChain}} where T<:PeaceFounder.Model.Transaction","page":"PeaceFounder.Model","title":"PeaceFounder.Model.select","text":"select(T, predicate::Function, ledger::BraidChain)::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":"model_api/#PeaceFounder.Model.state-Tuple{PeaceFounder.Model.BraidChain}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.state","text":"state(ledger::BraidChain)\n\nReturn a current braidchain ledger state metadata.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.ticket-Tuple{PeaceFounder.Model.Member}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.ticket","text":"ticket(member::Member)\n\nTicket for a member admission certificate.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.BraidWork","page":"PeaceFounder.Model","title":"PeaceFounder.Model.BraidWork","text":"struct BraidWork <: Transaction\n braid::Simulator\n consumer::DemeSpec\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; consumer denotes a deme for which the braid is intended and 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_api/#PeaceFounder.Model.approve-Tuple{PeaceFounder.Model.BraidWork, PeaceFounder.Model.Signer}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.approve","text":"approve(braid::BraidWork, 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_api/#PeaceFounder.Model.braid-Tuple{PeaceFounder.Model.Generator, Union{Set{PeaceFounder.Model.Pseudonym}, Vector{PeaceFounder.Model.Pseudonym}}, PeaceFounder.Model.DemeSpec, PeaceFounder.Model.DemeSpec}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.input_generator-Tuple{PeaceFounder.Model.BraidWork}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.input_generator","text":"input_generator(braid::BraidWork)\n\nReturn input generator of the braid.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.input_members-Tuple{PeaceFounder.Model.BraidWork}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.input_members","text":"input_members(braid::BraidWork)\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_api/#PeaceFounder.Model.output_generator-Tuple{PeaceFounder.Model.BraidWork}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.output_generator","text":"output_generator(braid::BraidWork)\n\nReturn output genertor of the braid.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.output_members-Tuple{PeaceFounder.Model.BraidWork}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.output_members","text":"output_members(braid::BraidWork)\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_api/#PeaceFounder.Model.verify-Tuple{PeaceFounder.Model.BraidWork, PeaceFounder.Model.CryptoSpec}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.verify","text":"verify(braid::BraidWork, 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_api/#Ballot-Box","page":"PeaceFounder.Model","title":"Ballot Box","text":"","category":"section"},{"location":"model_api/","page":"PeaceFounder.Model","title":"PeaceFounder.Model","text":"Modules = [PeaceFounder.Model]\nOrder = [:type, :function]\nPages = [\"Model/proposals.jl\"]","category":"page"},{"location":"model_api/#PeaceFounder.Model.Ballot","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.BallotBox","page":"PeaceFounder.Model","title":"PeaceFounder.Model.BallotBox","text":"mutable struct BallotBox\n proposal::Proposal\n voters::Set{Pseudonym} # better than members\n collector::Pseudonym\n seed::Union{Digest, Nothing}\n crypto::CryptoSpec # on the other hand the inclusion of a vote should be binding enough as it includes proposal hash.\n queue::Vector{Vote}\n ledger::Vector{CastRecord}\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, members, ledger, spine, index, seed, leaf, root, record, 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":"model_api/#PeaceFounder.Model.BallotBoxState","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.CastAck","page":"PeaceFounder.Model","title":"PeaceFounder.Model.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_api/#PeaceFounder.Model.CastReceipt","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.CastRecord","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.PollingStation","page":"PeaceFounder.Model","title":"PeaceFounder.Model.PollingStation","text":"struct PollingStation\n halls::Vector{BallotBox}\n crypto::CryptoSpec\nend\n\nRepresents a pooling station which hosts ballotbox ledgers for every proposal collector manages. \n\nInterface: add!, ballotbox, record!, commit!, commit, ack_leaf, ack_root, ack_cast, record, receipt, spine, ledger, tally, set_seed!\n\n\n\n\n\n","category":"type"},{"location":"model_api/#PeaceFounder.Model.Proposal","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.Selection","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.Tally","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.Vote","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#Base.length-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"Base.length","text":"length(ledger::BallotBox)\n\nReturn a total length of the ledger including uncommited records in the queue.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#Base.push!-Tuple{PeaceFounder.Model.BallotBox, PeaceFounder.Model.CastRecord}","page":"PeaceFounder.Model","title":"Base.push!","text":"push!(ledger::BallotBox, 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":"model_api/#HistoryTrees.leaf-Tuple{PeaceFounder.Model.BallotBox, Int64}","page":"PeaceFounder.Model","title":"HistoryTrees.leaf","text":"leaf(ledger::BallotBox, N::Int)::Digest\n\nReturn a record digest used to form a history tree.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#HistoryTrees.root-Tuple{PeaceFounder.Model.BallotBox, Int64}","page":"PeaceFounder.Model","title":"HistoryTrees.root","text":"root(ledger::BallotBox[, 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":"model_api/#HistoryTrees.root-Tuple{PeaceFounder.Model.BallotBoxState}","page":"PeaceFounder.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_api/#PeaceFounder.Model.ack_cast-Tuple{PeaceFounder.Model.BallotBox, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.ack_cast","text":"ack_cast(ledger::BallotBox, index::Int)::CastAck\n\nCompute an acknowledgment for record inclusion at index.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.ack_cast-Tuple{PeaceFounder.Model.PollingStation, Base.UUID, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.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":"model_api/#PeaceFounder.Model.ack_leaf-Tuple{PeaceFounder.Model.BallotBox, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.ack_leaf","text":"ack_leaf(ledger::BallotBox, index::Int)::AckInclusion\n\nCompute an inclusion proof ::AckInclusion for record element at given index.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.ack_leaf-Tuple{PeaceFounder.Model.PollingStation, Base.UUID, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.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":"model_api/#PeaceFounder.Model.ack_root-Tuple{PeaceFounder.Model.BallotBox, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.ack_root","text":"ack_root(ledger::BallotBox, index::Int)::AckConsistency\n\nCompute a history tree consistency proof at index. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.ack_root-Tuple{PeaceFounder.Model.PollingStation, Base.UUID, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.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":"model_api/#PeaceFounder.Model.add!-Tuple{PeaceFounder.Model.PollingStation, PeaceFounder.Model.Proposal, Set{PeaceFounder.Model.Pseudonym}, PeaceFounder.Model.Pseudonym}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.add!","text":"add!(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":"model_api/#PeaceFounder.Model.ballotbox-Tuple{PeaceFounder.Model.PollingStation, Base.UUID}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.ballotbox","text":"ballotbox(station::PollingStation, uuid::UUID)::BallotBox\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":"model_api/#PeaceFounder.Model.ballotbox-Tuple{PeaceFounder.Model.PollingStation, PeaceFounder.Model.Digest}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.ballotbox","text":"ballotbox(station::PollingStation, proposal::Digest)::BallotBox\n\nReturn a ballotbox which has proposal with provided digest.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.commit!-Tuple{PeaceFounder.Model.BallotBox, Dates.DateTime, PeaceFounder.Model.Signer}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.commit!","text":"commit!(ledger::BallotBox[, 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":"model_api/#PeaceFounder.Model.commit!-Tuple{PeaceFounder.Model.PollingStation, Base.UUID, PeaceFounder.Model.Signer}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.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":"model_api/#PeaceFounder.Model.commit-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.commit","text":"commit(ledger::BallotBox)\n\nReturn a commit for the ballotbox ledger.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.commit-Tuple{PeaceFounder.Model.CastAck}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.commit","text":"commit(ack::CastAck)\n\nReturn a commit from a CastAck.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.commit-Tuple{PeaceFounder.Model.PollingStation, Base.UUID}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.commit","text":"commit(station::PollingStation, uuid::UUID)::Commit\n\nReturn a ballotbox commit.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.commit_index-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.commit_index","text":"commit_index(ledger::BallotBox)::Union{Index, Nothing}\n\nIndex at which commit is issued. See also length and index\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.commit_state-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.commit_state","text":"commit_state(ledger::BallotBox)\n\nReturn a committed state for a ballotbox ledger.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.generator-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.generator","text":"generator(ledger::BallotBox)\n\nReturn a relative generator which members use to sign votes anchored by the proposal.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.generator-Tuple{PeaceFounder.Model.Proposal}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.index-Tuple{PeaceFounder.Model.BallotBoxState}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.index-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.index","text":"index(ledger::BallotBox)\n\nReturn the current index of the ledger. See also length.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.isbinding-Tuple{PeaceFounder.Model.BraidChain, PeaceFounder.Model.ChainState}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.isbinding","text":"isbinding(chain::BraidChain, state::ChainState)::Bool\n\nCheck that chain state is consistent with braidchain ledger.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.isbinding-Tuple{PeaceFounder.Model.CastAck, PeaceFounder.Model.Proposal, PeaceFounder.Model.Hash}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.isbinding","text":"isbinding(ack::CastAck, proposal::Proposal, hasher::Hash)::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_api/#PeaceFounder.Model.isbinding-Tuple{PeaceFounder.Model.CastReceipt, PeaceFounder.Model.AckInclusion, PeaceFounder.Model.Hash}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.isbinding","text":"isbinding(receipt::CastReceipt, ack::AckInclusion, hasher::Hash)::Bool\n\nCheck that cast receipt is binding to received inclusion acknowledgment.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.isbinding-Tuple{PeaceFounder.Model.CastReceipt, PeaceFounder.Model.Vote, PeaceFounder.Model.Hash}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.isbinding","text":"isbinding(receipt::CastReceipt, vote::Vote, hasher::Hash)::Bool\n\nCheck that the receipt is bidning to a vote. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.isbinding-Tuple{PeaceFounder.Model.Vote, PeaceFounder.Model.CastAck, PeaceFounder.Model.CryptoSpec}","page":"PeaceFounder.Model","title":"PeaceFounder.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":"model_api/#PeaceFounder.Model.isbinding-Tuple{PeaceFounder.Model.Vote, PeaceFounder.Model.Proposal, PeaceFounder.Model.CryptoSpec}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.isbinding","text":"isbinding(vote::Vote, proposal::Proposal, crypto::CryptoSpec)\n\nCheck that the vote is bound to a proposal.. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.isconsistent-Tuple{PeaceFounder.Model.Selection, PeaceFounder.Model.Ballot}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.issuer-Tuple{PeaceFounder.Model.Proposal}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.issuer","text":"issuer(proposal::Proposal)\n\nIssuer of approval for the proposal.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.ledger-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.ledger","text":"ledger(ballotbox::BallotBox)::Vector{CastRecord}\n\nReturn all records from a ballotbox ledger.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.ledger-Tuple{PeaceFounder.Model.PollingStation, Base.UUID}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.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":"model_api/#PeaceFounder.Model.members-Tuple{Any}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.members","text":"members(ledger::BallotBox)\n\nReturn a list of member pseudonyms with which members authetificate their votes.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.pseudonym-Tuple{PeaceFounder.Model.Vote}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.receipt-Tuple{PeaceFounder.Model.BallotBox, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.receipt","text":"receipt(ledger::BallotBox, index::Int)::CastReceipt\n\nReturn a receipt for a ledger element.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.receipt-Tuple{PeaceFounder.Model.CastRecord, PeaceFounder.Model.Hash}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.receipt","text":"receipt(record::CastRecord, hasher::Hash)::CastReceipt\n\nConstruct a CastReceipt from a CastRecord with a provided hasher function.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.receipt-Tuple{PeaceFounder.Model.PollingStation, Base.UUID, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.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":"model_api/#PeaceFounder.Model.record!-Tuple{PeaceFounder.Model.BallotBox, PeaceFounder.Model.CastRecord}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.record!","text":"record!(ledger::BallotBox, 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":"model_api/#PeaceFounder.Model.record!-Tuple{PeaceFounder.Model.BallotBox, PeaceFounder.Model.Vote}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.record!","text":"record!(ledger::BallotBox, 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":"model_api/#PeaceFounder.Model.record!-Tuple{PeaceFounder.Model.PollingStation, Base.UUID, PeaceFounder.Model.Vote}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.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":"model_api/#PeaceFounder.Model.record!-Tuple{PeaceFounder.Model.PollingStation, PeaceFounder.Model.Vote}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.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":"model_api/#PeaceFounder.Model.record-Tuple{PeaceFounder.Model.BallotBox, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.record","text":"record(ledger::BallotBox, index::Int)::CastRecord\n\nReturn a ledger record at provided index.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.record-Tuple{PeaceFounder.Model.PollingStation, Base.UUID, Int64}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.record","text":"record(station::PollingStation, uuid::UUID, N::Int)::CastRecord\n\nReturn a record with an index N at ballotbox with uuid.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.reset_tree!-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.reset_tree!","text":"reset_tree!(ledger::BallotBox)\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":"model_api/#PeaceFounder.Model.seed-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.seed","text":"seed(ledger::BallotBox)::Union{Digest, Nothing}\n\nReturn a random selected seed used in the voting.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.set_seed!-Tuple{PeaceFounder.Model.BallotBox, PeaceFounder.Model.Digest}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.set_seed!","text":"set_seed!(ledger::BallotBox, seed::Digest)\n\nSet's a seed of the ballotbox.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.set_seed!-Tuple{PeaceFounder.Model.PollingStation, Base.UUID, PeaceFounder.Model.Digest}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.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":"model_api/#PeaceFounder.Model.spine-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.spine","text":"spine(ledger::BallotBox)::Vector{Digest}\n\nReturn a history tree leaf vector.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.spine-Tuple{PeaceFounder.Model.PollingStation, Base.UUID}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.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":"model_api/#PeaceFounder.Model.state-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.state","text":"state(ledger::BallotBox; with_tally::Union{Nothing, Bool} = nothing)::BallotBoxState\n\nReturn a state metadata for ballotbox ledger. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.state-Tuple{PeaceFounder.Model.Proposal}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.tally-Tuple{PeaceFounder.Model.Ballot, AbstractVector{PeaceFounder.Model.Selection}}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.tally-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.tally","text":"tally(ledger::BallotBox)\n\nCompute a tally for a ballotbox ledger. \n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.tally-Tuple{PeaceFounder.Model.PollingStation, Base.UUID}","page":"PeaceFounder.Model","title":"PeaceFounder.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":"model_api/#PeaceFounder.Model.uuid-Tuple{PeaceFounder.Model.BallotBox}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.uuid","text":"uuid(ledger::BallotBox)\n\nReturn a UUID of the proposal.\n\n\n\n\n\n","category":"method"},{"location":"model_api/#PeaceFounder.Model.uuid-Tuple{PeaceFounder.Model.Proposal}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.validate-Tuple{PeaceFounder.Model.BallotBox, PeaceFounder.Model.Vote}","page":"PeaceFounder.Model","title":"PeaceFounder.Model.validate","text":"validate(ledger::BallotBox, 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":"model_api/#PeaceFounder.Model.verify-Tuple{PeaceFounder.Model.CastAck, PeaceFounder.Model.CryptoSpec}","page":"PeaceFounder.Model","title":"PeaceFounder.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_api/#PeaceFounder.Model.vote-Tuple{PeaceFounder.Model.Proposal, PeaceFounder.Model.Digest, PeaceFounder.Model.Selection, PeaceFounder.Model.Signer}","page":"PeaceFounder.Model","title":"PeaceFounder.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":"#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":"A major hurdle in mainstream E2E (end-to-end) e-voting system designs is a multiparty protocol ceremony coordination required for initiating a threshold decryption key and performing decryption at the end of the vote. The voter's anonymity demands independence of the involved parties, which introduces a risk of sabotage where election results could be left undecrypted and unannounced. Moreover, due to the need to encode ballot selection in a group element, only a limited number of ballot types can be supported and face challenges, for instance, for cardinal and budget planning ballots. This is even more restrictive when a homomorphic counting procedure is employed.","category":"page"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"An alternative approach is to anonymise voter's credentials instead of the votes. The idea has been explored with blind signature schemes, but auditing the authority's issuance of signatures and detecting key leaks remains unresolved. A subsequent method, proposed by Haenni & Spycher, leverages ElGamal re-encryption to verifiably exponentiate voters' public keys in tandem with a generator using zero-knowledge proofs. Together with a history tree bulletin board implementation, it forms the foundation for the design of the PeaceFounder voting system.","category":"page"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"The PeaceFounder voting system builds upon the foundational work of Haenni & Spycher, serving as a practical implementation of their proposal. Nevertheless, PeaceFounder introduces several key features:","category":"page"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"A scalable bulletin board design with thin-member clients ensuring the immutability of all published records without replication;\nA registration protocol for new members that catches them up with the current relative generator;\nMechanisms to handle uncooperative bulletin boards through auditors/proxies while preventing potential exploitation by coercers and bribers with time-restricted receipt freeness and revoting;\nA system allowing a member's device to detect private key leaks coming from spyware or bad cryptography via sequence numbers and bitmasks;\nA malware detection mechanism post-voting, where the device displayed receipt, is compared to a bulletin board while not being deceived into verifying another voter's vote.","category":"page"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"Furthermore, PeaceFounder demonstrates that a single maintainer can feasibly deploy the system. That is possible due to the lack of a multi-party ceremony and member device accountability of the bulletin board. It also offers seamless integration opportunities with existing infrastructure and political environment for supporting different ways proposals are put to the ballot box, and member authenticity is verified and later audited. Additionally, the PeaceFounder showcases user experience for the voter, minimising their exposure to complex byte strings while maintaining cryptographic soundness along with other usability improvements. ","category":"page"},{"location":"#Demo","page":"PeaceFounder.jl","title":"Demo","text":"","category":"section"},{"location":"","page":"PeaceFounder.jl","title":"PeaceFounder.jl","text":"For a demo, go to the PeaceFounderDemo repository. A 10-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":"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 for the votes specified in the DemeSpec fields.","category":"page"},{"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. This 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 would be 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":"
      \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"}] } diff --git a/dev/setup/index.html b/dev/setup/index.html index 3643617..abafc44 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.