Skip to content

Commit

Permalink
Fix/guardian proof (#432)
Browse files Browse the repository at this point in the history
* Add ParameterBaseHash constant and Election Variable

Add the ParameterBaseHash as a static member to the compiled code as well as to the CiphertextElectionContext as a serialized member since we must maintain compatibility with different elections using different parameters for this value.

* Add Parameter Hash and sequence ordering to Schnorr proofs

add parameter hash and sequence ordering to schnorr challenges and propagate the necessary dependencies down the stack

* reimplement schnorr response calculation

* Added comments to 2 methods to get rid of the linter issues since this file was touched in this PR

* add xml comments

* fixed spacing issue

* fixing spacing issue

* cleaned up linter warnings

* Add back original constructor and test for missing parameter hash

---------

Co-authored-by: SteveMaier-IRT <[email protected]>
Co-authored-by: Steve Maier <[email protected]>
  • Loading branch information
3 people authored Sep 25, 2023
1 parent 47c52ae commit 99ced18
Show file tree
Hide file tree
Showing 28 changed files with 749 additions and 263 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,27 @@ public static class CoefficientExtensions
/// Generate a Coefficient for testing purposes only.
/// In a production environment, nonce should be null and a random value will be generated.
/// </summary>
public static Coefficient GenerateCoefficient(ElementModQ nonce, int index)
public static Coefficient GenerateCoefficient(ulong offset, int index, ElementModQ parameterHash, ElementModQ seed)
{
Console.WriteLine("WARNING: GenerateCoefficient using a predetermined nonce for testing purposes only. This should not be used in production.");
var value = BigMath.AddModQ(nonce, (ulong)index);
return new(value);
var secret = BigMath.AddModQ(seed, (ulong)index);
return new(offset, index, parameterHash, secret);
}

/// <summary>
/// Generate a Coefficient for testing purposes only.
/// In a production environment, nonce should be null and a random value will be generated.
/// </summary>
/// <param name="nonce">A predetermined nonce parameter for testing purposes only.</param>
/// <param name="secret">A predetermined nonce parameter for testing purposes only.</param>
/// <param name="index">The index of the coefficient</param>
/// <param name="seed">A predetermined seed for testing purposes only.</param>
public static Coefficient GenerateCoefficient(ElementModQ nonce, ElementModQ seed, int index)
public static Coefficient GenerateCoefficient(
ulong offset, int index, ElementModQ parameterHash, ElementModQ nonce, ElementModQ seed)
{
Console.WriteLine("WARNING: GenerateCoefficient using a predetermined nonce for testing purposes only. This should not be used in production.");
var value = BigMath.AddModQ(nonce, (ulong)index);
Console.WriteLine($"value: {value}");
return new(value, seed);
var secret = BigMath.AddModQ(nonce, (ulong)index);
Console.WriteLine($"value: {secret}");
return new(offset, index, parameterHash, secret, seed);
}
}

Expand All @@ -35,15 +36,19 @@ public static class PolynomialExtensions
/// Generate a Polynomial for testing purposes only.
/// In a production environment, nonce should be null and a random value will be generated.
/// </summary>
/// <param name="nonce">A predetermined nonce parameter for testing purposes only.</param>
/// <param name="secret">A predetermined nonce parameter for testing purposes only.</param>
/// <param name="quorum">The number of coefficients in the polynomial</param>
public static ElectionPolynomial GeneratePolynomial(ElementModQ nonce, int quorum)
public static ElectionPolynomial GeneratePolynomial(ulong sequenceOrder, int quorum, ElementModQ secret)
{
Console.WriteLine("WARNING: GeneratePolynomial using a predetermined nonce for testing purposes only. This should not be used in production.");
var coefficients = new List<Coefficient>();
for (var i = 0; i < quorum; i++)
{
coefficients.Add(CoefficientExtensions.GenerateCoefficient(nonce, i));
coefficients.Add(CoefficientExtensions.GenerateCoefficient(
sequenceOrder,
i,
CiphertextElectionContext.ParameterBaseHash,
secret));
}
return new(coefficients);
}
Expand All @@ -52,16 +57,21 @@ public static ElectionPolynomial GeneratePolynomial(ElementModQ nonce, int quoru
/// Generate a Polynomial for testing purposes only.
/// In a production environment, nonce should be null and a random value will be generated.
/// </summary>
/// <param name="nonce">A predetermined nonce parameter for testing purposes only.</param>
/// <param name="secret">A predetermined nonce parameter for testing purposes only.</param>
/// <param name="quorum">The number of coefficients in the polynomial</param>
/// <param name="seed">A predetermined seed for testing purposes only.</param>
public static ElectionPolynomial GeneratePolynomial(ElementModQ nonce, ElementModQ seed, int quorum)
public static ElectionPolynomial GeneratePolynomial(ulong sequenceOrder, int quorum, ElementModQ secret, ElementModQ seed)
{
Console.WriteLine("WARNING: GeneratePolynomial using a predetermined nonce for testing purposes only. This should not be used in production.");
var coefficients = new List<Coefficient>();
for (var i = 0; i < quorum; i++)
{
coefficients.Add(CoefficientExtensions.GenerateCoefficient(nonce, seed, i));
coefficients.Add(CoefficientExtensions.GenerateCoefficient(
sequenceOrder,
i,
CiphertextElectionContext.ParameterBaseHash,
secret,
seed));
}
return new(coefficients);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public static List<Guardian> GenerateGuardians(
sequenceOrder,
keyCeremony.NumberOfGuardians,
keyCeremony.Quorum,
CiphertextElectionContext.ParameterBaseHash,
keyCeremony.Id,
random);
guardians.Add(guardian);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ public class TestElectionPolynomial
public void Test_ElectionPolynomial_Constructs_WithDegrees()
{
// Arrange
var sequenceOrder = 2UL;
var degrees = 2;
var parameterHash = Constants.TWO_MOD_Q;

// Act
var result = new ElectionPolynomial(degrees);
var result = new ElectionPolynomial(sequenceOrder, degrees, parameterHash);

// Assert
Assert.That(result, Is.Not.Null);
Expand All @@ -20,11 +22,13 @@ public void Test_ElectionPolynomial_Constructs_WithDegrees()
public void Test_ElectionPolynomial_Constructs_WithSecretKey()
{
// Arrange
var sequenceOrder = 2UL;
var degrees = 2;
var parameterHash = Constants.TWO_MOD_Q;
var secretKey = Constants.TWO_MOD_Q;

// Act
var result = new ElectionPolynomial(degrees, secretKey);
var result = new ElectionPolynomial(sequenceOrder, degrees, parameterHash, secretKey);

// Assert
Assert.That(result, Is.Not.Null);
Expand All @@ -36,12 +40,14 @@ public void Test_ElectionPolynomial_Constructs_WithSecretKey()
public void Test_ElectionPolynomial_Constructs_WithKeyPair()
{
// Arrange
var sequenceOrder = 2UL;
var degrees = 3;
var parameterHash = Constants.TWO_MOD_Q;
using var secretKey = BigMath.RandQ();
using var keyPair = new ElGamalKeyPair(secretKey);

// Act
using var result = new ElectionPolynomial(degrees, keyPair);
using var result = new ElectionPolynomial(sequenceOrder, degrees, parameterHash, keyPair);

// Assert
Assert.That(result, Is.Not.Null);
Expand All @@ -55,11 +61,12 @@ public void Test_ElectionPolynomial_Constructs_WithKeyPair()
public void Test_ElectionPolynomial_ComputeCoordinate()
{
// Arrange
var offset = 0UL;
var coordinate = 1UL;
var degrees = 2;
var nonce = Constants.ONE_MOD_Q;
var seed = Constants.TWO_MOD_Q;
var polynomial = PolynomialExtensions.GeneratePolynomial(nonce, seed, degrees);
var polynomial = PolynomialExtensions.GeneratePolynomial(offset, degrees, nonce, seed);

// Act
var result = polynomial.ComputeCoordinate(coordinate);
Expand All @@ -73,9 +80,11 @@ public void Test_ElectionPolynomial_ComputeCoordinate()
public void Test_ElectionPolynomial_VerifyCoordinate()
{
// Arrange
var sequenceOrder = 2UL;
var coordinate = 1UL;
var degrees = 2UL;
var polynomial = new ElectionPolynomial((int)degrees);
var parameterHash = Constants.TWO_MOD_Q;
var polynomial = new ElectionPolynomial(sequenceOrder, (int)degrees, parameterHash);
var expected = polynomial.ComputeCoordinate(coordinate);

// Act
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@ public void Test_KeyCeremony()
var guardianId = sequenceOrder.ToString();
var random = new Random((int)sequenceOrder);
var guardian = new Guardian(
guardianId, sequenceOrder, numberOfGuardians,
quorum, keyCeremony.Id,
guardianId, sequenceOrder,
numberOfGuardians,
quorum,
CiphertextElectionContext.ParameterBaseHash,
keyCeremony.Id,
random);
guardians.Add(guardian);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ namespace ElectionGuard.ElectionSetup;
/// </summary>
public class Coefficient : DisposableBase
{
/// <summary>
/// The offset of the secret value in the polynomial (i in the spec)
/// </summary>
public ulong Offset { get; set; }

/// <summary>
/// The index of the proof corresponding to the coefficient (j in the spec)
/// </summary>
public int Index { get; set; }

/// <summary>
/// The key pair associated with the coefficient
/// </summary>
Expand All @@ -31,72 +41,85 @@ public class Coefficient : DisposableBase
public SchnorrProof Proof { get; private set; } = default!;

/// <summary>
/// Generate a coefficient with a predetermined value
/// Generate a coefficient with a predetermined secret
/// </summary>
public Coefficient(ElementModQ value)
public Coefficient(
ulong offset,
int index,
ElementModQ parameterHash,
ElementModQ secret)
{
var keyPair = ElGamalKeyPair.FromSecret(value);
Proof = new SchnorrProof(keyPair);
Offset = offset;
Index = index;
var keyPair = ElGamalKeyPair.FromSecret(secret);
Proof = new SchnorrProof(offset, index, parameterHash, keyPair);
KeyPair = new ElGamalKeyPair(keyPair);
}

/// <summary>
/// Generate a coefficient with a predetermined value and proof seed
/// Generate a coefficient with a predetermined secret and proof seed
/// </summary>
public Coefficient(ElementModQ value, ElementModQ seed)
public Coefficient(
ulong offset,
int index,
ElementModQ parameterHash,
ElementModQ secret, ElementModQ seed)
{
var keyPair = ElGamalKeyPair.FromSecret(value);
Proof = new SchnorrProof(keyPair, seed);
Offset = offset;
Index = index;
var keyPair = ElGamalKeyPair.FromSecret(secret);
Proof = new SchnorrProof(offset, index, parameterHash, keyPair, seed);
KeyPair = new ElGamalKeyPair(keyPair);
}

/// <summary>
/// Generate a coefficient with a predetermined value and proof
/// Generate a coefficient with a predetermined secret and proof
/// </summary>
public Coefficient(ElementModQ value, SchnorrProof proof)
public Coefficient(
ulong offset,
int index,
ElementModQ parameterHash,
ElementModQ secret, SchnorrProof proof)
{
if (!proof.IsValid())
if (!proof.IsValid(offset, index, parameterHash).Success)
{
throw new ArgumentException("Invalid proof");
}

var keyPair = ElGamalKeyPair.FromSecret(value);
var keyPair = ElGamalKeyPair.FromSecret(secret);
if (!proof.PublicKey.Equals(keyPair.PublicKey))
{
throw new ArgumentException("Proof does not match key pair");
}

Offset = offset;
Index = index;
KeyPair = new ElGamalKeyPair(keyPair);
Proof = new(proof);
}

[JsonConstructor]
public Coefficient(ElGamalKeyPair keyPair, SchnorrProof proof)
public Coefficient(
ulong offset,
int index,
ElGamalKeyPair keyPair, SchnorrProof proof)
{
if (!proof.IsValid())
{
throw new ArgumentException("Invalid proof");
}

// Dos not check the proof for validity when serializing from json
if (!proof.PublicKey.Equals(keyPair.PublicKey))
{
throw new ArgumentException("Proof does not match key pair");
}

Offset = offset;
Index = index;
KeyPair = new ElGamalKeyPair(keyPair);
Proof = new(proof);
}

public Coefficient(Coefficient that)

{
KeyPair = new ElGamalKeyPair(that.KeyPair);
Proof = new SchnorrProof(that.Proof);
}
public Coefficient(Coefficient other)

public bool IsValid()
{
return Proof.IsValid() && Proof.PublicKey.Equals(KeyPair.PublicKey);
KeyPair = new ElGamalKeyPair(other.KeyPair);
Proof = new SchnorrProof(other.Proof);
}

protected override void DisposeUnmanaged()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,14 @@ public string OwnerId
public ElectionKeyPair(
string ownerId,
ulong sequenceOrder,
int quorum)
int quorum,
ElementModQ parameterHash)
{
GuardianId = ownerId;
SequenceOrder = sequenceOrder;
using var randQ = BigMath.RandQ();
KeyPair = new(randQ);
Polynomial = new ElectionPolynomial(quorum, KeyPair);
Polynomial = new ElectionPolynomial(sequenceOrder, quorum, parameterHash, KeyPair);
}

/// <summary>
Expand All @@ -62,25 +63,27 @@ public ElectionKeyPair(
string ownerId,
ulong sequenceOrder,
int quorum,
ElementModQ parameterHash,
ElGamalKeyPair keyPair)
{
GuardianId = ownerId;
SequenceOrder = sequenceOrder;
KeyPair = new(keyPair);
Polynomial = new(quorum, keyPair);
Polynomial = new(sequenceOrder, quorum, parameterHash, keyPair);
}

public ElectionKeyPair(
string ownerId,
ulong sequenceOrder,
int quorum,
ElementModQ parameterHash,
ElGamalKeyPair keyPair,
Random random)
{
GuardianId = ownerId;
SequenceOrder = sequenceOrder;
KeyPair = new(keyPair);
Polynomial = new(quorum, keyPair, random);
Polynomial = new(sequenceOrder, quorum, parameterHash, keyPair, random);
}

/// <summary>
Expand Down Expand Up @@ -118,8 +121,6 @@ public ElectionKeyPair(
SequenceOrder = sequenceOrder;
KeyPair = new(keyPair.SecretKey, keyPair.PublicKey);
Polynomial = new(polynomial);

// TODO: verify the polynomial is valid for the keypair
}

public ElectionKeyPair(ElectionKeyPair other)
Expand All @@ -128,8 +129,6 @@ public ElectionKeyPair(ElectionKeyPair other)
SequenceOrder = other.SequenceOrder;
KeyPair = new(other.KeyPair.SecretKey, other.KeyPair.PublicKey);
Polynomial = new(other.Polynomial);

// TODO: verify the polynomial is valid for the keypair
}

public ElectionPublicKey Share()
Expand Down
Loading

0 comments on commit 99ced18

Please sign in to comment.