/// <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 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."); } }
public void VoteVerifyTest() { for (int i = 0; i < 100; i++) { this.publicKey = parameters.Random(); Vote vote = new Vote(0, this.parameters.Random(), this.parameters, this.publicKey, new Progress(null)); Assert.IsTrue(vote.Verify(this.publicKey, this.parameters, RandomNumberGenerator.Create(), BaseParameters.StandardProofCount)); } }
public void VoteInvalidVerifyTest() { for (int i = 0; i < 100; i++) { this.publicKey = parameters.Random(); Vote vote0 = new Vote(2, this.parameters.Random(), this.parameters, this.publicKey, FakeType.BadDisjunction); Assert.IsFalse(vote0.Verify(this.publicKey, this.parameters, RandomNumberGenerator.Create(), BaseParameters.StandardProofCount)); Vote vote1 = new Vote(2, this.parameters.Random(), this.parameters, this.publicKey, FakeType.BadFiatShamir); Assert.IsFalse(vote1.Verify(this.publicKey, this.parameters, RandomNumberGenerator.Create(), BaseParameters.StandardProofCount)); Vote vote2 = new Vote(2, this.parameters.Random(), this.parameters, this.publicKey, FakeType.BadPowerMod); Assert.IsFalse(vote2.Verify(this.publicKey, this.parameters, RandomNumberGenerator.Create(), BaseParameters.StandardProofCount)); } }
/// <summary> /// Partially deciphers a vote. /// </summary> /// <remarks> /// Observes multiply/divide for linear combination with other /// partial deciphers. /// </remarks> /// <param name="vote">Vote to partially decipher.</param> /// <param name="multiply">Linear combination multiplicator.</param> /// <param name="divide">Linear combination dividend.</param> /// <returns>Partial decipher value.</returns> private BigInt PartialDecipher(Vote vote, int multiply, int divide) { if (vote == null) throw new ArgumentNullException("vote"); if (divide == 0) throw new ArgumentException("Divide cannot be 0."); CryptoLog.Begin(CryptoLogLevel.Numeric, "Creating partial decipher"); CryptoLog.Add(CryptoLogLevel.Numeric, "Vote halfkey", vote.HalfKey); CryptoLog.Add(CryptoLogLevel.Numeric, "Multiply", multiply); CryptoLog.Add(CryptoLogLevel.Numeric, "Divide", divide); CryptoLog.Add(CryptoLogLevel.Secret, "Secret key part", this.secretKeyPart); //The 12 magic number is inserted to avoid division remainders when //dividing partial deciphers for linear combinations by 2, 3 and 4. var value = vote.HalfKey.PowerMod(this.secretKeyPart * 12 * multiply / divide, this.parameters.P); CryptoLog.Add(CryptoLogLevel.Numeric, "Value", value); CryptoLog.End(CryptoLogLevel.Numeric); return value; }
/// <summary> /// Creates all partial deciphers for a vote. /// </summary> /// <remarks> /// Partial deciphers from t+1 authority with the same index are /// to be combined to fully decipher the vote. /// </remarks> /// <param name="vote">Vote to partially decipher.</param> /// <returns>List of partial deciphers.</returns> public IEnumerable<PartialDecipher> PartialDeciphers(int authorityIndex, Vote vote, int questionIndex, int optionIndex) { if (vote == null) throw new ArgumentNullException("vote"); if (!questionIndex.InRange(0, parameters.Questions.Count() - 1)) throw new ArgumentException("Option index must be in range 0..OptionCount-1."); if (!optionIndex.InRange(0, parameters.Questions.ElementAt(questionIndex).Options.Count() - 1)) throw new ArgumentException("Option index must be in range 0..OptionCount-1."); List<PartialDecipher> partialDeciphers = new List<PartialDecipher>(); //The magic numbers for multiply and divide listed here for //each authority index and partial decipher group index //are computed to provide linear combinations of the partial //decipher that yield a full decipher. // //Example for 5 authorities and threshold 3. //f1-f5 polynoms of authorities 1-5 // //each autority j has shares f1(j) to f5(j) which expand to //a polynomial of degree 3, namely f1(j) = a0+a1*j+a2*j^2+a3*j^3 //these shares are summed as x(j) = f1(j)+f2(j)+f3(j)+f4(j)+f5(j) // //these are then linarly combined to the secret key: //x(1)*4 + x(2)*-6 + x(3)*4 + x(4)*-1 = ... = a0(1)+a0(2)+a0(3)+a(4)+a(5) switch (Index) { case 1: partialDeciphers.Add(new PartialDecipher(authorityIndex, 2, questionIndex, optionIndex, PartialDecipher(vote, 5, 2))); partialDeciphers.Add(new PartialDecipher(authorityIndex, 3, questionIndex, optionIndex, PartialDecipher(vote, 10, 3))); partialDeciphers.Add(new PartialDecipher(authorityIndex, 4, questionIndex, optionIndex, PartialDecipher(vote, 15, 4))); partialDeciphers.Add(new PartialDecipher(authorityIndex, 5, questionIndex, optionIndex, PartialDecipher(vote, 4, 1))); break; case 2: partialDeciphers.Add(new PartialDecipher(authorityIndex, 1, questionIndex, optionIndex, PartialDecipher(vote, 10, 1))); partialDeciphers.Add(new PartialDecipher(authorityIndex, 3, questionIndex, optionIndex, PartialDecipher(vote, -10, 3))); partialDeciphers.Add(new PartialDecipher(authorityIndex, 4, questionIndex, optionIndex, PartialDecipher(vote, -5, 1))); partialDeciphers.Add(new PartialDecipher(authorityIndex, 5, questionIndex, optionIndex, PartialDecipher(vote, -6, 1))); break; case 3: partialDeciphers.Add(new PartialDecipher(authorityIndex, 1, questionIndex, optionIndex, PartialDecipher(vote, -20, 1))); partialDeciphers.Add(new PartialDecipher(authorityIndex, 2, questionIndex, optionIndex, PartialDecipher(vote, -5, 1))); partialDeciphers.Add(new PartialDecipher(authorityIndex, 4, questionIndex, optionIndex, PartialDecipher(vote, 5, 2))); partialDeciphers.Add(new PartialDecipher(authorityIndex, 5, questionIndex, optionIndex, PartialDecipher(vote, 4, 1))); break; case 4: partialDeciphers.Add(new PartialDecipher(authorityIndex, 1, questionIndex, optionIndex, PartialDecipher(vote, 15, 1))); partialDeciphers.Add(new PartialDecipher(authorityIndex, 2, questionIndex, optionIndex, PartialDecipher(vote, 5, 1))); partialDeciphers.Add(new PartialDecipher(authorityIndex, 3, questionIndex, optionIndex, PartialDecipher(vote, 5, 3))); partialDeciphers.Add(new PartialDecipher(authorityIndex, 5, questionIndex, optionIndex, PartialDecipher(vote, -1, 1))); break; case 5: partialDeciphers.Add(new PartialDecipher(authorityIndex, 1, questionIndex, optionIndex, PartialDecipher(vote, -4, 1))); partialDeciphers.Add(new PartialDecipher(authorityIndex, 2, questionIndex, optionIndex, PartialDecipher(vote, -3, 2))); partialDeciphers.Add(new PartialDecipher(authorityIndex, 3, questionIndex, optionIndex, PartialDecipher(vote, -2, 3))); partialDeciphers.Add(new PartialDecipher(authorityIndex, 4, questionIndex, optionIndex, PartialDecipher(vote, -1, 4))); break; default: throw new InvalidOperationException("Bad authority index."); } return partialDeciphers; }
/// <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> /// Add two votes to a new one. /// </summary> /// <param name="a">A vote.</param> /// <param name="b">Another vote.</param> public Vote(Vote a, Vote b) { if (a == null) throw new ArgumentNullException("a"); if (b == null) throw new ArgumentNullException("b"); P = a.P; HalfKey = (a.HalfKey * b.HalfKey).Mod(P); Ciphertext = (a.Ciphertext * b.Ciphertext).Mod(P); RangeProves = new List<RangeProof>(); }