tinyvote module
Minimal pure-Python library that demonstrates a basic encrypted voting workflow by leveraging a secure multi-party computation (MPC) protocol.
- class tinyvote.tinyvote.node[source]
Bases:
object
Data structure for maintaining the information associated with a node and performing node operations.
Suppose that a secure decentralized voting workflow is supported by three parties. The
node
objects would be instantiated locally by each of these three parties.>>> nodes = [node(), node(), node()]
The preprocessing workflow that the nodes must execute can be simulated using the
preprocess
function. The number of voters that the workflow supports must be known, and it is assumed that all permitted choices are integers greater than or equal to0
and strictly less than a fixed maximum value. The number of voters and the number of distinct choices must be supplied to thepreprocess
function.>>> preprocess(nodes, votes=4, choices=2)
Each voter must then submit a request for the opportunity to submit their vote. The voters can create
request
instances for this purpose. In the example below, each of the four voters creates such a request.>>> request_zero = request(identifier=0) >>> request_one = request(identifier=1) >>> request_two = request(identifier=2) >>> request_three = request(identifier=3)
Each voter can deliver their request to each node, and each node can then locally use its
masks
method to generate masks that can be returned to the requesting voter.>>> masks_zero = [node.masks(request_zero) for node in nodes] >>> masks_one = [node.masks(request_one) for node in nodes] >>> masks_two = [node.masks(request_two) for node in nodes] >>> masks_three = [node.masks(request_three) for node in nodes]
Each voter can then generate locally a
vote
instance (i.e., a masked vote choice).>>> vote_zero = vote(masks_zero, 0) >>> vote_one = vote(masks_one, 1) >>> vote_two = vote(masks_two, 1) >>> vote_three = vote(masks_three, 1)
Every voter can broadcast its masked vote choice to all the nodes. Each node can locally assemble these as they arrive. Once a node has received all masked votes, it can determine its shares of the overall tally of the votes using the
outcome
method.>>> shares = [ ... node.outcome([vote_zero, vote_one, vote_two, vote_three]) ... for node in nodes ... ]
The overall outcome can be reconstructed from the shares by the voting workflow operator using the
reveal
function. The outcome is represented as alist
in which each entry contains the tally for the choice corresponding to the entry’s index.>>> reveal(shares) [1, 3]
- class tinyvote.tinyvote.request(identifier)[source]
-
Data structure for representing a request to submit a vote. A request can be submitted to each node to obtain corresponding masks for a vote.
- Parameters
identifier (
int
) – Integer identifying the requesting voter.
The example below demonstrates how requests can be created.
>>> request(identifier=1), ([(0, 1)],) >>> request(identifier=3), ([(0, 3)],)
- class tinyvote.tinyvote.vote(masks, choice)[source]
Bases:
List
[Dict
[Tuple
[int
,int
],modulo
]]Data structure for representing a vote that can be broadcast to nodes.
- Parameters
Suppose masks have already been obtained from the nodes via the steps below.
>>> nodes = [node(), node(), node()] >>> preprocess(nodes, votes=4, choices=3) >>> identifier = 2 >>> choice = 2 >>> masks = [node.masks(request(identifier)) for node in nodes]
This method can be used to mask the vote choice (in preparation for broadcasting it to the nodes).
>>> isinstance(vote(masks, choice), vote) True
- tinyvote.tinyvote.preprocess(nodes, votes, choices)[source]
Simulate a preprocessing workflow among the supplied nodes for a workflow that supports the specified number of votes and distinct choices (where choices are assumed to be integers greater than or equal to
0
and strictly less than the valuechoices
).- Parameters
The example below performs a preprocessing workflow involving three nodes.
>>> nodes = [node(), node(), node()] >>> preprocess(nodes, votes=4, choices=3)
- tinyvote.tinyvote.reveal(shares)[source]
Reconstruct the overall tally of votes from the shares obtained from each node.
- Parameters
shares (
List
[List
[modulo
]]) – Shares of overall outcome tally (where each share is a list of components, with one component per permitted choice).
Suppose the shares below are returned from the three nodes in a workflow.
>>> from modulo import modulo >>> p = 4215209819 >>> shares = [ ... [modulo(3, p), modulo(5, p), modulo(4, p)], ... [modulo(1, p), modulo(2, p), modulo(9, p)], ... [modulo(8, p), modulo(0, p), modulo(8, p)] ... ]
This method combines such shares into an overall outcome by reconstructing the individual components and returning a list representing a tally of the total number of votes for each choice.
>>> reveal(shares) [3, 2, 4]