/// <summary> /// Creates a new encrypted vote. /// </summary> /// <remarks> /// Includes zero-knowledge proof of vote being 0 or 1. /// Still need non-interactive zero-knowledge proof of sum of votes. /// </remarks> /// <param name="votum">Actual vote.</param> /// <param name="parameters">Cryptographic parameters.</param> /// <param name="publicKey">Public key of the authorities.</param> /// <param name="progress">Report the progress up.</param> public Vote(int votum, BigInt nonce, BaseParameters parameters, BigInt publicKey, Progress progress) { if (!votum.InRange(0, 1)) throw new ArgumentException("Bad votum."); if (nonce == null) throw new ArgumentNullException("nonce"); if (parameters == null) throw new ArgumentNullException("parameters"); if (publicKey == null) throw new ArgumentNullException("publicKey"); P = parameters.P; HalfKey = parameters.G.PowerMod(nonce, P); //The 12 magic number is inserted to avoid division remainders when //dividing partial deciphers for linear combinations by 2, 3 and 4. Ciphertext = (publicKey.PowerMod(nonce * 12, P) * parameters.F.PowerMod(votum, P)).Mod(P); RangeProves = new List<RangeProof>(); for (int proofIndex = 0; proofIndex < parameters.ProofCount; proofIndex++) { RangeProves.Add(new RangeProof(votum, nonce * 12, this, publicKey, parameters)); progress.Add(1d / (double)parameters.ProofCount); } }
/// <summary> /// Creates a new ballot for a voter. /// </summary> /// <param name="vota">Vota the voter wishes to cast for each option.</param> /// <param name="parameters">Cryptographic parameters.</param> /// <param name="publicKey">Public key of voting authorities.</param> /// <param name="progress">Report progress up.</param> public Ballot(IEnumerable<int> vota, BaseParameters parameters, Question questionParameters, BigInt publicKey, Progress progress) { if (progress == null) throw new ArgumentNullException("progress"); if (vota == null) throw new ArgumentNullException("vota"); if (parameters == null) throw new ArgumentNullException("parameters"); if (publicKey == null) throw new ArgumentNullException("publicKey"); if (vota.Count() != questionParameters.Options.Count()) throw new ArgumentException("Bad vota."); if (!vota.All(votum => votum.InRange(0, 1))) throw new ArgumentException("Bad vota."); if (vota.Sum() != questionParameters.MaxVota) throw new ArgumentException("Bad vota."); Votes = new List<Vote>(); BigInt nonceSum = new BigInt(0); Vote voteSum = null; List<Tuple<int, BigInt, BaseParameters, BigInt>> voteWorkList = new List<Tuple<int, BigInt, BaseParameters, BigInt>>(); foreach (int votum in vota) { BigInt nonce = parameters.Random(); nonceSum += nonce; voteWorkList.Add(new Tuple<int, BigInt, BaseParameters, BigInt>(votum, nonce, parameters, publicKey)); } progress.Down(1d / (vota.Count() + 1) * vota.Count()); List<Vote> voteList = Parallel .Work<Tuple<int, BigInt, BaseParameters, BigInt>, Vote>(CreateVote, voteWorkList, progress.Set); progress.Up(); foreach (Vote vote in voteList) { voteSum = voteSum == null ? vote : voteSum + vote; Votes.Add(vote); } progress.Down(1d / (double)(vota.Count() + 1)); SumProves = new List<Proof>(); for (int proofIndex = 0; proofIndex < parameters.ProofCount; proofIndex++) { SumProves.Add(new Proof(nonceSum * 12, voteSum, publicKey, parameters)); progress.Add(1d / (double)parameters.ProofCount); } progress.Up(); }
/// <summary> /// Verifies the correctness of the ballot. /// </summary> /// <remarks> /// Verifies all proof for sum and range of votes. /// </remarks> /// <param name="publicKey">Public key of the authorities.</param> /// <param name="parameters">Cryptographic parameters.</param> /// <param name="questionParameters">Parameters of the question.</param> /// <param name="rng">Random number generator.</param> /// <param name="proofCheckCount">Number of proofs to check.</param> /// <param name="progress">Reports on the progress.</param> /// <returns>Result of the verification.</returns> public bool Verify(BigInt publicKey, BaseParameters parameters, Question questionParameters, RandomNumberGenerator rng, int proofCheckCount, Progress progress) { if (publicKey == null) throw new ArgumentNullException("publicKey"); if (parameters == null) throw new ArgumentNullException("parameters"); if (questionParameters == null) throw new ArgumentNullException("questionParameters"); bool verifies = true; Vote voteSum = null; CryptoLog.Begin(CryptoLogLevel.Detailed, "Verifying ballot"); CryptoLog.Add(CryptoLogLevel.Detailed, "Question", questionParameters.Text.Text); foreach (Vote vote in Votes) { verifies &= vote.Verify(publicKey, parameters, rng, proofCheckCount); voteSum = voteSum == null ? vote : voteSum + vote; progress.Add(1d / (double)Votes.Count); } verifies &= SumProves.Count == parameters.ProofCount; verifies &= SumProves .SelectRandom(rng, proofCheckCount) .All(sumProof => sumProof.Verify(voteSum, publicKey, parameters, questionParameters)); CryptoLog.Add(CryptoLogLevel.Numeric, "Public key", publicKey); CryptoLog.Add(CryptoLogLevel.Numeric, "Vote sum ciphertext", voteSum.Ciphertext); CryptoLog.Add(CryptoLogLevel.Numeric, "Vote sum halfkey", voteSum.HalfKey); CryptoLog.Add(CryptoLogLevel.Detailed, "Verified", verifies); CryptoLog.End(CryptoLogLevel.Detailed); return verifies; }