Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/guardian proof #432

Merged
merged 12 commits into from
Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I considered using a default value throughout in the interface but decided against that and to force the application to provide this value because it is runtime dependent (even though it is a compiled constant). This way, the caller is forced to understand that we have a dependency on the values G,Q, and P that are used to make the guardian. Really this probably should be part of the key ceremony and then the guardian can derive agains the key ceremony but i was trying to minimize the number of changes.

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