/// <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> /// Adds a vote to the vote sum. /// </summary> /// <remarks> /// Verfies the correctness of the vote first. /// </remarks> /// <param name="envelopeIndex">Index of the envelope.</param> /// <param name="signedEnvelope">Signed envelope from voter.</param> /// <param name="progress">Report the progress of the tallying.</param> public void Add(int envelopeIndex, Signed<Envelope> signedEnvelope, Progress progress) { if (signedEnvelope == null) throw new ArgumentNullException("signedEnvelope"); if (voteSums == null) throw new InvalidOperationException("Must call TallyBegin first."); CryptoLog.Begin(CryptoLogLevel.Detailed, "Tallying envelope"); CryptoLog.Add(CryptoLogLevel.Detailed, "Envelope index", envelopeIndex); CryptoLog.Add(CryptoLogLevel.Detailed, "Certificate id", signedEnvelope.Certificate.Id); CryptoLog.Add(CryptoLogLevel.Numeric, "Certificate fingerprint", signedEnvelope.Certificate.Fingerprint); CryptoLog.Add(CryptoLogLevel.Detailed, "Certificate type", signedEnvelope.Certificate.TypeText); if (signedEnvelope.Certificate is VoterCertificate) { CryptoLog.Add(CryptoLogLevel.Detailed, "Certificate group id", ((VoterCertificate)signedEnvelope.Certificate).GroupId); } bool acceptVote = true; Envelope envelope = signedEnvelope.Value; //Certificate is of voter and valid for that canton. acceptVote &= signedEnvelope.Certificate is VoterCertificate && ((VoterCertificate)signedEnvelope.Certificate).GroupId == this.parameters.GroupId; //Signature must be valid. acceptVote &= signedEnvelope.Verify(this.certificateStorage, envelope.Date); CryptoLog.Add(CryptoLogLevel.Detailed, "Certificate status", signedEnvelope.Certificate.Validate(this.certificateStorage, envelope.Date).Text()); CryptoLog.Add(CryptoLogLevel.Detailed, "Envelope signature", signedEnvelope.Verify(this.certificateStorage, envelope.Date)); //Voter's vote must not have been counted. acceptVote &= !this.countedVoters.Contains(signedEnvelope.Certificate.Id); CryptoLog.Add(CryptoLogLevel.Detailed, "Already voted", this.countedVoters.Contains(signedEnvelope.Certificate.Id)); //Date must be in voting period. acceptVote &= envelope.Date.Date >= this.parameters.VotingBeginDate; acceptVote &= envelope.Date.Date <= this.parameters.VotingEndDate; CryptoLog.Add(CryptoLogLevel.Detailed, "Envelope date", envelope.Date); //Ballot must verify (prooves). for (int questionIndex = 0; questionIndex < this.parameters.Questions.Count(); questionIndex++) { Question question = this.parameters.Questions.ElementAt(questionIndex); Ballot ballot = envelope.Ballots.ElementAt(questionIndex); progress.Down(1d / (double)this.parameters.Questions.Count()); acceptVote &= ballot.Verify(this.publicKey, this.parameters, question, this.rng, this.proofCheckCount, progress); progress.Up(); } CryptoLog.Add(CryptoLogLevel.Detailed, "Envelope accepted", acceptVote); CryptoLog.EndWrite(); lock (this.envelopeSequencerList) { this.envelopeSequencerList.Add(envelopeIndex, new Tuple<Signed<Envelope>,bool>(signedEnvelope, acceptVote)); } AddInSequence(); }