/// <summary> /// Creates a new sum proof. /// </summary> /// <param name="r">The randomness used to encrypt the vote.</param> /// <param name="voteSum">The sum of all votes for which to generate a proof.</param> /// <param name="publicKey">The public key with which the vote was encrypted.</param> /// <param name="parameters">Cryptographic Parameters.</param> public Proof(BigInt r, Vote voteSum, BigInt publicKey, BaseParameters parameters) { if (r == null) throw new ArgumentNullException("r"); if (voteSum == null) throw new ArgumentNullException("vote"); if (publicKey == null) throw new ArgumentNullException("publicKey"); if (parameters == null) throw new ArgumentNullException("parameters"); BigInt r0 = parameters.Random(); T0 = publicKey.PowerMod(r0, parameters.P); MemoryStream serializeStream = new MemoryStream(); SerializeContext serializer = new SerializeContext(serializeStream); serializer.Write(voteSum.Ciphertext); serializer.Write(voteSum.HalfKey); serializer.Write(publicKey); serializer.Write(T0); serializer.Close(); serializeStream.Close(); SHA512Managed sha512 = new SHA512Managed(); byte[] hash = sha512.ComputeHash(serializeStream.ToArray()); C0 = hash[0] | (hash[1] << 8); S0 = r0 + r * C0; }
/// <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 sum proof. /// </summary> /// <param name="r">The randomness used to encrypt the vote.</param> /// <param name="voteSum">The sum of all votes for which to generate a proof.</param> /// <param name="publicKey">The public key with which the vote was encrypted.</param> /// <param name="parameters">Cryptographic Parameters.</param> /// /// <param name="fakeType">What fake to create?</param> public Proof(BigInt r, Vote voteSum, BigInt publicKey, BaseParameters parameters, FakeType fakeType) { if (r == null) throw new ArgumentNullException("r"); if (voteSum == null) throw new ArgumentNullException("vote"); if (publicKey == null) throw new ArgumentNullException("publicKey"); if (parameters == null) throw new ArgumentNullException("parameters"); BigInt r0 = parameters.Random(); MemoryStream serializeStream = new MemoryStream(); SerializeContext serializer = new SerializeContext(serializeStream); SHA512Managed sha512 = new SHA512Managed(); switch (fakeType) { case FakeType.BadFiatShamir: T0 = publicKey.PowerMod(r0, parameters.P); serializer.Write(voteSum.Ciphertext); serializer.Write(voteSum.HalfKey); serializer.Write(publicKey); serializer.Write(T0); serializer.Close(); serializeStream.Close(); byte[] hash0 = sha512.ComputeHash(serializeStream.ToArray()); C0 = 0; S0 = r0 + r * C0; break; case FakeType.BadPowerMod: T0 = publicKey.PowerMod(0, parameters.P); serializer.Write(voteSum.Ciphertext); serializer.Write(voteSum.HalfKey); serializer.Write(publicKey); serializer.Write(T0); serializer.Close(); serializeStream.Close(); byte[] hash1 = sha512.ComputeHash(serializeStream.ToArray()); C0 = hash1[0] | (hash1[1] << 8); S0 = 1; break; default: throw new NotSupportedException("Cannot generate that type of fake."); } }
/// <summary> /// Create a new authority. /// </summary> /// <param name="index">Index of new authority. Must be at least one.</param> /// <param name="parameters">Cryptographic parameters.</param> public Authority(int index, BaseParameters parameters) { if (parameters == null) throw new ArgumentNullException("parameters"); if (!index.InRange(1, parameters.AuthorityCount)) throw new ArgumentException("Index must be in range 1..AuthorityCount."); Index = index; this.parameters = parameters; }
public Authority(DeserializeContext context, BaseParameters parameters) { Index = context.ReadInt32(); this.polynomial = context.ReadObject<Polynomial>(); if (!context.ReadBoolean()) { this.secretKeyPart = context.ReadBigInt(); } this.parameters = parameters; }
/// <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; }
/// <summary> /// Verify this share of the secret. /// </summary> /// <param name="authorityIndex">Index of the verifying authority.</param> /// <param name="parameters">Cryptographic parameters.</param> /// <param name="polynomial">Polynomial to verify against.</param> /// <param name="verificationValues">Verification values. Also known as A(i)(j).</param> /// <returns>Was share accepted?</returns> public bool Verify(int authorityIndex, BaseParameters parameters, List<VerificationValue> verificationValues) { if (verificationValues == null) throw new ArgumentNullException("verificationValues"); if (verificationValues .Any(verificationValueList => verificationValueList == null)) throw new ArgumentException("No verification value can be null."); if (verificationValues.Count != parameters.Thereshold + 1) throw new ArgumentException("Bad verificaton value count."); if (DestinationAuthorityIndex != authorityIndex) return false; BigInt GtoS = parameters.G.PowerMod(Value, parameters.P); BigInt aProduct = new BigInt(1); for (int k = 0; k <= parameters.Thereshold; k++) { VerificationValue verificationValue = verificationValues[k]; if (verificationValue.SourceAuthorityIndex != SourceAuthorityIndex) return false; aProduct *= verificationValue.Value.PowerMod(new BigInt(authorityIndex).PowerMod(new BigInt(k), parameters.P), parameters.P); aProduct = aProduct.Mod(parameters.P); } return GtoS == aProduct; }
/// <summary> /// Verifies a sum proof. /// </summary> /// <param name="voteSum">The vote sum for which to verify the proof.</param> /// <param name="publicKey">Public key against which to verify the proof.</param> /// <param name="parameters">Cryptographic Parameters.</param> /// <returns>Wether the proof is valid.</returns> public bool Verify(Vote voteSum, BigInt publicKey, BaseParameters parameters, Question questionParameters) { if (voteSum == null) throw new ArgumentNullException("vote"); if (publicKey == null) throw new ArgumentNullException("publicKey"); if (parameters == null) throw new ArgumentNullException("parameters"); CryptoLog.Begin(CryptoLogLevel.Detailed, "Verifying sum proof"); CryptoLog.Add(CryptoLogLevel.Numeric, "C", C0); CryptoLog.Add(CryptoLogLevel.Numeric, "T", T0); if (!C0.InRange(0, 0xffff)) { CryptoLog.Add(CryptoLogLevel.Detailed, "Verified", false); CryptoLog.End(CryptoLogLevel.Detailed); return false; } MemoryStream serializeStream = new MemoryStream(); SerializeContext serializer = new SerializeContext(serializeStream); serializer.Write(voteSum.Ciphertext); serializer.Write(voteSum.HalfKey); serializer.Write(publicKey); serializer.Write(T0); serializer.Close(); serializeStream.Close(); SHA512Managed sha512 = new SHA512Managed(); byte[] hash = sha512.ComputeHash(serializeStream.ToArray()); CryptoLog.Add(CryptoLogLevel.Numeric, "SHA 512", hash); if (C0 != (hash[0] | (hash[1] << 8))) { CryptoLog.Add(CryptoLogLevel.Detailed, "Verified", false); CryptoLog.End(CryptoLogLevel.Detailed); return false; } if (publicKey.PowerMod(S0, parameters.P) != (T0 * voteSum.Ciphertext.DivideMod(parameters.F.PowerMod(questionParameters.MaxVota, parameters.P), parameters.P).PowerMod(C0, parameters.P)).Mod(parameters.P)) { CryptoLog.Add(CryptoLogLevel.Detailed, "Verified", false); CryptoLog.End(CryptoLogLevel.Detailed); return false; } CryptoLog.Add(CryptoLogLevel.Detailed, "Verified", true); CryptoLog.End(CryptoLogLevel.Detailed); return true; }
/// <summary> /// Creates a new range proof. /// </summary> /// <param name="votum">The votum. Must be 0 or 1.</param> /// <param name="r">The randomness used to encrypt the vote.</param> /// <param name="vote">The vote for which to generate a proof.</param> /// <param name="publicKey">The public key with which the vote was encrypted.</param> /// <param name="parameters">Cryptographic Parameters.</param> public RangeProof(int votum, BigInt r, Vote vote, BigInt publicKey, BaseParameters parameters) { if (r == null) throw new ArgumentNullException("r"); if (vote == null) throw new ArgumentNullException("vote"); if (publicKey == null) throw new ArgumentNullException("publicKey"); if (parameters == null) throw new ArgumentNullException("parameters"); BigInt r0 = parameters.Random(); BigInt r1 = parameters.Random(); switch (votum) { case 0: //Create the fake proof. C1 = (int)Prime.RandomNumber(16); S1 = parameters.Random(); T1 = (vote.Ciphertext.DivideMod(parameters.F.PowerMod(1, parameters.P), parameters.P).PowerMod(C1, parameters.P).InvertMod(parameters.P) * publicKey.PowerMod(S1, parameters.P)).Mod(parameters.P); //First part of the real proof T0 = publicKey.PowerMod(r0, parameters.P); break; case 1: //Create the fake proof. C0 = (int)Prime.RandomNumber(16); S0 = parameters.Random(); T0 = (vote.Ciphertext.DivideMod(parameters.F.PowerMod(0, parameters.P), parameters.P).PowerMod(C0, parameters.P).InvertMod(parameters.P) * publicKey.PowerMod(S0, parameters.P)).Mod(parameters.P); //First part of the real proof T1 = publicKey.PowerMod(r1, parameters.P); break; default: throw new ArgumentException("Bad votum."); } //Put togeather the data to be hashed. MemoryStream serializeStream = new MemoryStream(); SerializeContext serializer = new SerializeContext(serializeStream); serializer.Write(vote.Ciphertext); serializer.Write(vote.HalfKey); serializer.Write(publicKey); serializer.Write(T0); serializer.Write(T1); serializer.Close(); serializeStream.Close(); //Hash the proof data. SHA512Managed sha512 = new SHA512Managed(); byte[] hash = sha512.ComputeHash(serializeStream.ToArray()); //Take the first 16 bits. C = hash[0] | (hash[1] << 8); switch (votum) { case 0: //Second part of the real proof C0 = (int)((BigInt)(C - C1)).Mod(0xffff); S0 = r0 + r * C0; break; case 1: //Second part of the real proof C1 = (int)((BigInt)(C - C0)).Mod(0xffff); S1 = r1 + r * C1; break; default: throw new ArgumentException("Bad votum."); } }
/// <summary> /// Verifies a range proof. /// </summary> /// <param name="vote">The vote for which to verify the proof.</param> /// <param name="publicKey">Public key against which to verify the proof.</param> /// <param name="parameters">Cryptographic Parameters.</param> /// <returns>Wether the proof is valid.</returns> public bool Verify(Vote vote, BigInt publicKey, BaseParameters parameters) { if (vote == null) throw new ArgumentNullException("vote"); if (publicKey == null) throw new ArgumentNullException("publicKey"); if (parameters == null) throw new ArgumentNullException("parameters"); CryptoLog.Begin(CryptoLogLevel.Detailed, "Verifying range proof"); CryptoLog.Add(CryptoLogLevel.Numeric, "C", C); CryptoLog.Add(CryptoLogLevel.Numeric, "C0", C0); CryptoLog.Add(CryptoLogLevel.Numeric, "C1", C1); CryptoLog.Add(CryptoLogLevel.Numeric, "T0", T0); CryptoLog.Add(CryptoLogLevel.Numeric, "T1", T1); if (!C.InRange(0, 0xffff)) { CryptoLog.Add(CryptoLogLevel.Detailed, "Verified", false); CryptoLog.End(CryptoLogLevel.Detailed); return false; } MemoryStream serializeStream = new MemoryStream(); SerializeContext serializer = new SerializeContext(serializeStream); serializer.Write(vote.Ciphertext); serializer.Write(vote.HalfKey); serializer.Write(publicKey); serializer.Write(T0); serializer.Write(T1); serializer.Close(); serializeStream.Close(); SHA512Managed sha512 = new SHA512Managed(); byte[] hash = sha512.ComputeHash(serializeStream.ToArray()); CryptoLog.Add(CryptoLogLevel.Numeric, "SHA512", hash); if (C != (hash[0] | (hash[1] << 8))) { CryptoLog.Add(CryptoLogLevel.Detailed, "Verified", false); CryptoLog.End(CryptoLogLevel.Detailed); return false; } if (((C0 + C1) % 0xffff) != C && !(C0 == 3 && (-C0 + C1) % 0xffff == C) && !(C1 == 3 && (C0 - C1) % 0xffff == C)) { CryptoLog.Add(CryptoLogLevel.Detailed, "Verified", false); CryptoLog.End(CryptoLogLevel.Detailed); return false; } if (publicKey.PowerMod(S0, parameters.P) != (T0 * vote.Ciphertext.DivideMod(parameters.F.PowerMod(0, parameters.P), parameters.P).PowerMod(C0, parameters.P)).Mod(parameters.P)) { CryptoLog.Add(CryptoLogLevel.Detailed, "Verified", false); CryptoLog.End(CryptoLogLevel.Detailed); return false; } if (publicKey.PowerMod(S1, parameters.P) != (T1 * vote.Ciphertext.DivideMod(parameters.F.PowerMod(1, parameters.P), parameters.P).PowerMod(C1, parameters.P)).Mod(parameters.P)) { CryptoLog.Add(CryptoLogLevel.Detailed, "Verified", false); CryptoLog.End(CryptoLogLevel.Detailed); return false; } CryptoLog.Add(CryptoLogLevel.Detailed, "Verified", true); CryptoLog.End(CryptoLogLevel.Detailed); return true; }
/// <summary> /// Creates a new invalid range proof. /// </summary> /// <remarks> /// Used to test proofing mechanism. /// </remarks> /// <param name="votum">The votum. Must NOT be 0 or 1.</param> /// <param name="r">The randomness used to encrypt the vote.</param> /// <param name="vote">The vote for which to generate a proof.</param> /// <param name="publicKey">The public key with which the vote was encrypted.</param> /// <param name="parameters">Cryptographic Parameters.</param> /// <param name="fakeType">What is to be wrong?</param> public RangeProof(int votum, BigInt r, Vote vote, BigInt publicKey, BaseParameters parameters, FakeType fakeType) { if (r == null) throw new ArgumentNullException("r"); if (vote == null) throw new ArgumentNullException("vote"); if (publicKey == null) throw new ArgumentNullException("publicKey"); if (parameters == null) throw new ArgumentNullException("parameters"); BigInt r0 = parameters.Random(); BigInt r1 = parameters.Random(); MemoryStream serializeStream = new MemoryStream(); SerializeContext serializer = new SerializeContext(serializeStream); SHA512Managed sha512 = new SHA512Managed(); switch (fakeType) { case FakeType.BadDisjunction: //The C value will not be correct as it is not considered. //Create the fake proof. C0 = (int)Prime.RandomNumber(16); S0 = parameters.Random(); T0 = (vote.Ciphertext.DivideMod(parameters.F.PowerMod(0, parameters.P), parameters.P).PowerMod(C0, parameters.P).InvertMod(parameters.P) * publicKey.PowerMod(S0, parameters.P)).Mod(parameters.P); //Create the fake proof. C1 = (int)Prime.RandomNumber(16); S1 = parameters.Random(); T1 = (vote.Ciphertext.DivideMod(parameters.F.PowerMod(1, parameters.P), parameters.P).PowerMod(C1, parameters.P).InvertMod(parameters.P) * publicKey.PowerMod(S1, parameters.P)).Mod(parameters.P); //Put togeather the data to be hashed. serializer.Write(vote.Ciphertext); serializer.Write(vote.HalfKey); serializer.Write(publicKey); serializer.Write(T0); serializer.Write(T1); serializer.Close(); serializeStream.Close(); //Hash the proof data. byte[] hash0 = sha512.ComputeHash(serializeStream.ToArray()); //Take the first 16 bits. C = hash0[0] | (hash0[1] << 8); break; case FakeType.BadFiatShamir: //The C value will not correspond to the hash. //Create the fake proof. C0 = (int)Prime.RandomNumber(16); S0 = parameters.Random(); T0 = (vote.Ciphertext.DivideMod(parameters.F.PowerMod(0, parameters.P), parameters.P).PowerMod(C0, parameters.P).InvertMod(parameters.P) * publicKey.PowerMod(S0, parameters.P)).Mod(parameters.P); //Create the fake proof. C1 = (int)Prime.RandomNumber(16); S1 = parameters.Random(); T1 = (vote.Ciphertext.DivideMod(parameters.F.PowerMod(1, parameters.P), parameters.P).PowerMod(C1, parameters.P).InvertMod(parameters.P) * publicKey.PowerMod(S1, parameters.P)).Mod(parameters.P); //Put togeather the data to be hashed. serializer.Write(vote.Ciphertext); serializer.Write(vote.HalfKey); serializer.Write(publicKey); serializer.Write(T0); serializer.Write(T1); serializer.Close(); serializeStream.Close(); //Hash the proof data. byte[] hash1 = sha512.ComputeHash(serializeStream.ToArray()); //Take the first 16 bits. C = C0 + C1; break; case FakeType.BadPowerMod: //Create the fake proof. C1 = (int)Prime.RandomNumber(16); S1 = parameters.Random(); T1 = (vote.Ciphertext.DivideMod(parameters.F.PowerMod(1, parameters.P), parameters.P).PowerMod(C1, parameters.P).InvertMod(parameters.P) * publicKey.PowerMod(S1, parameters.P)).Mod(parameters.P); //First part of the real proof T0 = publicKey.PowerMod(r0, parameters.P); //Put togeather the data to be hashed. serializer.Write(vote.Ciphertext); serializer.Write(vote.HalfKey); serializer.Write(publicKey); serializer.Write(T0); serializer.Write(T1); serializer.Close(); serializeStream.Close(); //Hash the proof data. byte[] hash2 = sha512.ComputeHash(serializeStream.ToArray()); //Take the first 16 bits. C = hash2[0] | (hash2[1] << 8); //Second part of the real proof C0 = (int)((BigInt)(C - C1)).Mod(0xffff); S0 = r0 + r * C0; break; default: throw new NotSupportedException("Cannot fake in that way."); } }
/// <summary> /// Crypto base test. /// </summary> /// <remarks> /// Only used during development. /// </remarks> public void BaseTest() { BigInt prime = Prime.Find(80); BigInt safePrime = Prime.FindSafe(88); BaseParameters parameters = new BaseParameters(); parameters.GenerateNumbers(Files.TestDataPath); Question question = new Question(new MultiLanguageString(string.Empty), new MultiLanguageString(string.Empty), new MultiLanguageString(string.Empty), 1); question.AddOption(new Option(new MultiLanguageString("Ja"), new MultiLanguageString(string.Empty), new MultiLanguageString(string.Empty))); question.AddOption(new Option(new MultiLanguageString("Nein"), new MultiLanguageString(string.Empty), new MultiLanguageString(string.Empty))); parameters.AddQuestion(question); Authority[] auths = new Authority[5]; for (int aI = 0; aI < parameters.AuthorityCount; aI++) { auths[aI] = new Authority(aI + 1, parameters); } foreach (Authority a in auths) { a.CreatePolynomial(); } foreach (Authority a in auths) { List<Share> shares = new List<Share>(); List<List<VerificationValue>> As = new List<List<VerificationValue>>(); foreach (Authority b in auths) { shares.Add(b.Share(a.Index)); As.Add(new List<VerificationValue>()); for (int l = 0; l <= parameters.Thereshold; l++) { As[As.Count - 1].Add(b.VerificationValue(l)); } } a.VerifySharing(shares, As); } BigInt publicKey = new BigInt(1); foreach (Authority a in auths) { publicKey = (publicKey * a.PublicKeyPart).Mod(parameters.P); } List<Ballot> ballots = new List<Ballot>(); ballots.Add(new Ballot(new int[] { 0, 1 }, parameters, question, publicKey, null)); ballots.Add(new Ballot(new int[] { 0, 1 }, parameters, question, publicKey, null)); ballots.Add(new Ballot(new int[] { 1, 0 }, parameters, question, publicKey, null)); ballots.Add(new Ballot(new int[] { 0, 1 }, parameters, question, publicKey, null)); ballots.Add(new Ballot(new int[] { 1, 0 }, parameters, question, publicKey, null)); ballots.Add(new Ballot(new int[] { 0, 1 }, parameters, question, publicKey, null)); if (!ballots.All(ballot => ballot.Verify(publicKey, parameters, question, RandomNumberGenerator.Create(), BaseParameters.StandardProofCount, new Progress(null)))) throw new Exception("Bad proof."); for (int optionIndex = 0; optionIndex < question.Options.Count(); optionIndex++) { IEnumerable<Vote> votes = ballots.Select(ballot => ballot.Votes[optionIndex]); Vote sum = null; votes.Foreach(vote => sum = sum == null ? vote : sum + vote); List<PartialDecipher> partialDeciphers = new List<PartialDecipher>(); auths.Foreach(authority => partialDeciphers.AddRange(authority.PartialDeciphers(1, sum, 0, optionIndex))); IEnumerable<BigInt> partialDeciphers0 = partialDeciphers .Where(partialDecipher => partialDecipher.GroupIndex == 1) .Select(partialDecipher => partialDecipher.Value); int v0 = sum.Decrypt(partialDeciphers0, parameters); IEnumerable<BigInt> partialDeciphers1 = partialDeciphers .Where(partialDecipher => partialDecipher.GroupIndex == 1) .Select(partialDecipher => partialDecipher.Value); int v1 = sum.Decrypt(partialDeciphers1, parameters); IEnumerable<BigInt> partialDeciphers2 = partialDeciphers .Where(partialDecipher => partialDecipher.GroupIndex == 1) .Select(partialDecipher => partialDecipher.Value); int v2 = sum.Decrypt(partialDeciphers2, parameters); IEnumerable<BigInt> partialDeciphers3 = partialDeciphers .Where(partialDecipher => partialDecipher.GroupIndex == 1) .Select(partialDecipher => partialDecipher.Value); int v3 = sum.Decrypt(partialDeciphers3, parameters); IEnumerable<BigInt> partialDeciphers4 = partialDeciphers .Where(partialDecipher => partialDecipher.GroupIndex == 1) .Select(partialDecipher => partialDecipher.Value); int v4 = sum.Decrypt(partialDeciphers4, parameters); if (v0 == v1 && v0 == v2 && v0 == v3 && v0 == v4) { throw new Exception("Everything ok."); } else { throw new Exception("Bad vote."); } } }
/// <summary> /// Calculates the result of the vote. /// </summary> /// <param name="votePower">Vote value equal to F^vote.</param> /// <param name="parameters">Cryptographic parameters.</param> /// <returns>Result of the vote.</returns> private static int Result(BigInt votePower, BaseParameters parameters) { if (votePower == null) throw new ArgumentNullException("votePower"); if (parameters == null) throw new ArgumentNullException("parameters"); int sumOfVotes = 0; while (parameters.F.PowerMod(new BigInt(sumOfVotes), parameters.P) != votePower) { sumOfVotes++; if (sumOfVotes > 10000) return -1; } return sumOfVotes; }
/// <summary> /// Verifies all range proves. /// </summary> /// <param name="publicKey">Public key to verify against.</param> /// <param name="parameters">Cryptographic Parameters.</param> /// <param name="rng">Random number generator.</param> /// <param name="proofCheckCount">Number of proofs to check.</param> /// <returns>All proves are valid.</returns> public bool Verify(BigInt publicKey, BaseParameters parameters, RandomNumberGenerator rng, int proofCheckCount) { if (publicKey == null) throw new ArgumentNullException("publicKey"); if (parameters == null) throw new ArgumentNullException("parameters"); bool verifies = true; CryptoLog.Begin(CryptoLogLevel.Detailed, "Verifying option"); CryptoLog.Add(CryptoLogLevel.Numeric, "Ciphertext", Ciphertext); CryptoLog.Add(CryptoLogLevel.Numeric, "Halfkey", HalfKey); verifies &= RangeProves.Count == parameters.ProofCount; verifies &= RangeProves .SelectRandom(rng, proofCheckCount) .All(proof => proof.Verify(this, publicKey, parameters)); CryptoLog.End(CryptoLogLevel.Detailed); return verifies; }
/// <summary> /// Decrypts a vote from partial deciphers. /// </summary> /// <param name="partialDeciphers">Partial deciphers from t+1 authorities.</param> /// <param name="parameters">Cryptographic parameters.</param> /// <returns>Result of the vote.</returns> public int Decrypt(IEnumerable<BigInt> partialDeciphers, BaseParameters parameters) { if (partialDeciphers == null) throw new ArgumentNullException("partialDeciphers"); if (parameters == null) throw new ArgumentNullException("parameters"); if (partialDeciphers.Count() != parameters.Thereshold + 1) throw new ArgumentException("Wrong number of partial deciphers."); CryptoLog.Begin(CryptoLogLevel.Numeric, "Calculating authority group result"); CryptoLog.Add(CryptoLogLevel.Numeric, "Ciphertext", Ciphertext); int index = 0; foreach (var partialDecipher in partialDeciphers) { CryptoLog.Add(CryptoLogLevel.Numeric, string.Format("Partial decipher {0}", index) , partialDecipher); index++; } BigInt votePower = Ciphertext; partialDeciphers.Foreach(partialDecipher => votePower = votePower.DivideMod(partialDecipher, P)); CryptoLog.Add(CryptoLogLevel.Numeric, "Vote power", votePower); int result = Result(votePower, parameters); CryptoLog.Add(CryptoLogLevel.Numeric, "Authority group result", result); CryptoLog.End(CryptoLogLevel.Numeric); return result; }