How to hook Solon secure voting into Liquid Feedback
In my previous blog post I explained the concept of delegated voting and how to make it work together with cryptographically secure e-voting algorithms. In this post I want to describe actual data flows of Liquid Feedback, and how a secure e-voting system like Solon could be hooked into it. For those of you potentially interested in contributing to Solon, I hope this gives a high level idea of the design.
Everything explained here already exists. The
liquid_feedback_patch/ creates these hooks into Liquid Feedback Core and alters the calculation procedure so that it counts the externally provided results. The 0.1 version of Solon is able to support this data flow and gives you a simple UI to cast votes via Solon. The small detail missing is the actual "secure" part, the current version is just a mockup demonstrating the idea. After this post I intend to write more about the Acquisti e-voting algorithm that I intend to implement as part of Solon.
I will not explain in detail everything how Liquid Feedback works, that is still "left as an exercise to the reader", as they said on math lectures. In practice, you can find out about LQFB by reading the documentation and live demo on LiquidFeedback.org and also by downloading it and testing it.
Liquid Feedback state machine
The above picture shows the states that a Liquid Feedback issue goes through. The first part contains various states related to issue drafting. The initiatives that are able to gather enough supporters ("enough" is configurable) then move into the voting state. Calculation is itself its own state, issues spend a few seconds in this state before results become available (it's not computationally that slow, just that the implementation is an asynchronous background job).
Finally, one of the initiatives is declared a winner, or sometimes no initiative wins. If I've understood correctly the latter happens only when an implicit "Status Quo" option gets more votes than any other initiative. In the Schulze Rank voting method it's also possible that initiatives are tied, the mailing list currently is active with discussion about what happens (and what should happen) in such cases, but it seems Liquid Feedback will also end up picking a winner even then, so as long as some initiative has more support than "Status Quo" ie "do nothing", then you end up in the "Finished with winner" state.
Liquid Feedback state machine with Solon patch
In this picture we see how the Solon patch alters Liquid Feedback state machine. In the default state it works just as before. But if you set
system_setting.ext_voting_service then you can let an external voting service provide secure e-voting. This introduces two new states:
private_voting_closed. We will learn about those in the following picture...
Liquid Feedback data flow
This picture shows a simplified data flow in an unpatched Liquid Feedback database. The frontend provides a user interface for casting votes. If the voter votes directly, then his vote is stored in the
vote table. Delegated votes are stored in
delegation table. If you read the previous blog post you remember that delegation can happen per issue, for all issues per topic, or for everything that happens within your organizational unit. All of these are stored in the same table.
When voting on an issue is closed, then the
delegation table is read to find everyone that have delegated their vote to someone else. These are added up as a "weight" on top of those voters that have cast a direct vote. The user interface even shows this as a small "+5" if you look at who voted what.
The Schulze rank is one of those voting methods that uses pairwise comparisons of all alternatives, so the results are now copied into an aptly named
battle table which the Schulze rank algorithm will use as input.
The issue is then put into
calculation state which means that a stored procedure applies the Schulze rank algorithm on the
battle table. As a result, all initiatives receive a
rank, and if the initiative with rank 1 also has more votes than Status Quo, then we end up in the
Liquid Feedback data flow with Solon patch
Finally, this is what happens if you use Liquid Feedback with the Solon patch, and run it side by side with the Solon 0.1 mockup version. Like I said, you can use the mockup version to execute these data flows, but there isn't any encryption there yet. For the purpose of this blog post, just consider the Solon server a black box - it could implement any secure e-voting system.
Like you remember from the previous blog post, the user now can to cast both public and private votes. The public votes are sent to Liquid Feedback and stored just like the votes are stored in the unpatched Liquid Feedback.
Another part of the user interface is dedicated to casting the private votes. Currently this is just a completely separate browser window, but of course in the future the same frontend client would handle both of these. The private votes are sent directly to the Solon system. We will discuss the encryption part separately, but note that the client has to do its own share of encryption already. (This is the same as for encrypted email - it has to be built in to your locally installed email client, otherwise there's no point.)
Note that when voting started Solon has already fetched the data for all initiatives from Liquid Feedback, so that it knows what alternatives users can vote on. (Also, it needs to digitally sign the content of each alternative, so that they can not be edited / tampered with after voting has started.)
Now, for the new Liquid Feedback states introduced by our patch, the following things happen:
When the issue moves into
public_voting_closed state, Solon will fetch information about all public votes. As you remember, when a user delegates his private vote, this information can then be used to figure out the "value" of that vote. Essentially the public delegated votes form a graph, and you can follow the path at the end of which there is a direct vote, which is then counted.
When the issue moves into
private_voting_closed state, then Solon will stop accepting private votes and calculation of results start. Depending on the cryptographic algorithm used, this could take some time.
In other words, public and private voting could close at the same time, but they could also close at different times. It turns out this is not just a technical necessity but a great new feature too. In Liquid Feedback today, if some user knows (in fact, in the unpatched Liquid Feedback he can to a large extent see it) that he controls a large amount of delegated votes, he could deceive his supporters. For instance, maybe you are a popular Green candidate that has been bribed by the nuclear power plant industry. You could then first submit a vote against building nuclear power plants, but one minute before voting closes you would then change your vote in favor of nuclear power - bringing with you all the votes delegated to you! When the private voting phase closes later than public voting, this is no longer possible. If a corrupt politician would try such a blatantly obvious trick, his followers would notice it and they would still have time left to change their delegated private votes.
When results are ready, Solon will insert them into the
battle table in the same format as an unpatched Liquid Feedback would. It then calls a stored procedure to set the issue into the
From here, the normal code execution picks up again. The Schulze rank is applied against the voting results as found in
battle table, and the rest works exactly as before.
I hope this gives a good overview of how Solon will work. If it didn't, please ask questions in the comments!