Skip to content

Commit

Permalink
Merge pull request #29 from HenrikWM/f-tests
Browse files Browse the repository at this point in the history
Adds tests
  • Loading branch information
HenrikWM committed Nov 30, 2020
2 parents 48c5163 + 4c5f196 commit ca5262a
Show file tree
Hide file tree
Showing 22 changed files with 798 additions and 97 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -359,4 +359,7 @@ MigrationBackup/
.ionide/

# Fody - auto-generated XML schema
FodyWeavers.xsd
FodyWeavers.xsd

# Benchmark Results
BenchmarkDotNet.Artifacts/
19 changes: 10 additions & 9 deletions AnonymousTokens.sln
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@ VisualStudioVersion = 16.0.30517.126
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client.Console", "samples\ClientServer\Client\Client.Console\Client.Console.csproj", "{CCB7635D-7D0F-4371-AC14-828E208790AF}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Client-side", "Client-side", "{E4DAF051-5F2C-458A-8AD3-2E0B1E7D3C52}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Server-side", "Server-side", "{FC4D5FE2-898D-4C67-8094-FDB6E71247CD}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4DDE2573-8947-4348-95B4-688102A8294D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AnonymousTokens.Client", "src\AnonymousTokens.Client\AnonymousTokens.Client.csproj", "{D98EB88A-9922-4AA5-8C97-6206C7196CD5}"
Expand Down Expand Up @@ -40,6 +36,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AnonymousTokens.Server", "s
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AnonymousTokens", "src\AnonymousTokens\AnonymousTokens.csproj", "{EAD6EEA6-8866-4D23-BCE0-891AEE53BE98}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AnonymousTokens.Benchmarks", "test\AnonymousTokens.Benchmarks\AnonymousTokens.Benchmarks.csproj", "{FE1684A8-5257-48B5-A067-836D75831D15}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -74,21 +72,24 @@ Global
{EAD6EEA6-8866-4D23-BCE0-891AEE53BE98}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EAD6EEA6-8866-4D23-BCE0-891AEE53BE98}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EAD6EEA6-8866-4D23-BCE0-891AEE53BE98}.Release|Any CPU.Build.0 = Release|Any CPU
{FE1684A8-5257-48B5-A067-836D75831D15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FE1684A8-5257-48B5-A067-836D75831D15}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FE1684A8-5257-48B5-A067-836D75831D15}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FE1684A8-5257-48B5-A067-836D75831D15}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{CCB7635D-7D0F-4371-AC14-828E208790AF} = {E4DAF051-5F2C-458A-8AD3-2E0B1E7D3C52}
{E4DAF051-5F2C-458A-8AD3-2E0B1E7D3C52} = {017DB04E-CA83-4400-90FD-4CA10428EC51}
{FC4D5FE2-898D-4C67-8094-FDB6E71247CD} = {017DB04E-CA83-4400-90FD-4CA10428EC51}
{CCB7635D-7D0F-4371-AC14-828E208790AF} = {017DB04E-CA83-4400-90FD-4CA10428EC51}
{D98EB88A-9922-4AA5-8C97-6206C7196CD5} = {4DDE2573-8947-4348-95B4-688102A8294D}
{E691A98B-3EBC-4AE7-8858-67601E805909} = {FC4D5FE2-898D-4C67-8094-FDB6E71247CD}
{A4143A14-789E-4AD0-BAD9-BF5B32E24EC7} = {FC4D5FE2-898D-4C67-8094-FDB6E71247CD}
{E691A98B-3EBC-4AE7-8858-67601E805909} = {017DB04E-CA83-4400-90FD-4CA10428EC51}
{A4143A14-789E-4AD0-BAD9-BF5B32E24EC7} = {017DB04E-CA83-4400-90FD-4CA10428EC51}
{E24CF8EE-6D9B-49AC-92A5-EB1F81FDAAA2} = {4FB09123-E5E6-4367-BEDD-FF3D9906A2BA}
{017DB04E-CA83-4400-90FD-4CA10428EC51} = {645EAD64-C3E7-41AA-B7E4-E423DFFCEEDF}
{EF827382-7F6E-4230-A917-9D11415ECAD6} = {4DDE2573-8947-4348-95B4-688102A8294D}
{EAD6EEA6-8866-4D23-BCE0-891AEE53BE98} = {4DDE2573-8947-4348-95B4-688102A8294D}
{FE1684A8-5257-48B5-A067-836D75831D15} = {4FB09123-E5E6-4367-BEDD-FF3D9906A2BA}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {EC41792F-67C9-4BD6-B598-E3E2ECDD924C}
Expand Down
15 changes: 10 additions & 5 deletions readme.md → README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,17 @@ This Proof-of-Concept contains:
- `dotnet run --project .\samples\ClientServer\Server\Server.TokenGeneration.Api\Server.TokenGeneration.Api.csproj`
- `dotnet run --project .\samples\ClientServer\Server\Server.TokenVerification.Api\Server.TokenVerification.Api.csproj`

## Roadmap
### Build and run benchmarks

- Test-coverage
- Performance-pass
- Investigate usage of `SecureRandom` - re-use vs instantiation per use
- Publish NuGet-package
After running `build.ps1` navigate to the benchmark project:

`cd test\AnonymousTokens.Benchmark`

Run all benchmarks:

`dotnet run -c Release --filter *`

When complete you will see the output generated in a new `BenchmarkDotNet.Artifacts\results` folder.

## Sources

Expand Down
6 changes: 3 additions & 3 deletions samples/ClientServer/Client/Client.Console/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

using AnonymousTokens.Protocol;
using AnonymousTokens.Client.Protocol;
using AnonymousTokens.Services.InMemory;

using AnonymousTokensConsole.ApiClients.TokenGeneration;
Expand Down Expand Up @@ -30,7 +30,7 @@ static async Task Main(string[] args)
var publicKeyStore = new InMemoryPublicKeyStore();
var publicKey = await publicKeyStore.GetAsync();

_initiator = new Initiator(publicKey);
_initiator = new Initiator();

// 1. Initiate communication with a masked point P = r*T = r*Hash(t)
var init = _initiator.Initiate(ecParameters.Curve);
Expand All @@ -42,7 +42,7 @@ static async Task Main(string[] args)
var (Q, proofC, proofZ) = await _tokenGenerationClient.GenerateTokenAsync(ecParameters.Curve, P);

// 3. Randomise the token Q, by removing the mask r: W = (1/r)*Q = k*T. Also checks that proof (c,z) is correct.
var W = _initiator.RandomiseToken(ecParameters, P, Q, proofC, proofZ, r);
var W = _initiator.RandomiseToken(ecParameters, publicKey, P, Q, proofC, proofZ, r);

// 4. Verify that the token (t,W) is correct.
var isVerified = await _tokenVerificationClient.VerifyTokenAsync(t, W);
Expand Down
80 changes: 48 additions & 32 deletions src/AnonymousTokens.Client/Protocol/Initiator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,35 @@
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Security;

using System;

namespace AnonymousTokens.Protocol
namespace AnonymousTokens.Client.Protocol
{
public class Initiator
public interface IInitiator
{
/// <summary>
/// Public key for the token scheme.
/// </summary>
private readonly ECPoint _K;
public (byte[] t, BigInteger r, ECPoint P) Initiate(ECCurve curve);
public bool VerifyProof(
X9ECParameters ecParameters,
ECPublicKeyParameters K,
ECPoint P,
ECPoint Q,
BigInteger c,
BigInteger z);
public ECPoint RandomiseToken(
X9ECParameters ecParameters,
ECPublicKeyParameters K,
ECPoint P,
ECPoint Q,
BigInteger c,
BigInteger z,
BigInteger r);
}

/// <summary>
/// Creates Initiator with the Public key.
/// </summary>
/// <param name="publicKeyParameters">Parameters containing the public key K.</param>
public Initiator(ECPublicKeyParameters publicKeyParameters)
public class Initiator : IInitiator
{
private readonly SecureRandom _random;

public Initiator()
{
_K = publicKeyParameters.Q;
_random = new SecureRandom();
}

/// <summary>
Expand All @@ -32,23 +43,24 @@ public Initiator(ECPublicKeyParameters publicKeyParameters)
/// <returns>The seed t for a random point, the initial mask r of the point, and the masked point P</returns>
public (byte[] t, BigInteger r, ECPoint P) Initiate(ECCurve curve)
{
var random = new SecureRandom();

BigInteger r = ECCurveRandomNumberGenerator.GenerateRandomNumber(curve, random);
BigInteger r = ECCurveRandomNumberGenerator.GenerateRandomNumber(curve, _random);

// Sample random bytes t such that x = hash(t) is a valid
// x-coordinate on the curve. Then T = HashToWeierstrassCurve(t).
var t = new byte[32];
byte[]? t = new byte[32];
ECPoint? T;
for (; ; )
{
random.NextBytes(t);
_random.NextBytes(t);
T = ECCurveHash.HashToWeierstrassCurve(curve, t);
if (T == null)
continue;
break;
}

if (T == null)
throw new AnonymousTokensException("Point T is null after unsuccessfull hashing");

// Compute P = r*T
ECPoint P = T.Multiply(r);
return (t, r, P);
Expand All @@ -58,50 +70,54 @@ public Initiator(ECPublicKeyParameters publicKeyParameters)
/// Used by the initiator. Verifies a transcript of a Chaum-Pedersen protocol instance, using the strong Fiat-Shamir transform.
/// </summary>
/// <param name="ecParameters">Curve parameters</param>
/// <param name="K">The public key parameters for the token scheme</param>
/// <param name="P">Point initially submitted by the initiator</param>
/// <param name="Q">Point received from the token service</param>
/// <param name="c">Claimed challenge from the Chaum-Pedersen proof</param>
/// <param name="z">Response from the Chaum-Pedersen proof</param>
/// <returns>Returns true if the proof is valid and otherwise returns false</returns>
public bool VerifyProof(X9ECParameters ecParameters, ECPoint P, ECPoint Q, BigInteger c, BigInteger z)
public bool VerifyProof(X9ECParameters ecParameters, ECPublicKeyParameters K, ECPoint P, ECPoint Q, BigInteger c, BigInteger z)
{
// Compute X = z*G + c*K = r*G
var X = ecParameters.G.Multiply(z).Add(_K.Multiply(c));
ECPoint? X = ecParameters.G.Multiply(z).Add(K.Q.Multiply(c));

// Compute Y = z*P + c*Q = r*P
var Y = P.Multiply(z).Add(Q.Multiply(c));
ECPoint? Y = P.Multiply(z).Add(Q.Multiply(c));

// Returns true if the challenge from the proof equals the new challenge
return c.Equals(CPChallengeGenerator.CreateChallenge(ecParameters.G, P, _K, Q, X, Y));
return c.Equals(CPChallengeGenerator.CreateChallenge(ecParameters.G, P, K.Q, Q, X, Y));
}

/// <summary>
/// Used by the initiator. It first verifies that the incoming token is well-formed, and then removes the previously applied mask.
/// </summary>
/// <param name="ecParameters">Curve parameters</param>
/// <param name="K">The public key parameters for the token scheme</param>
/// <param name="P">Masked point initially submitted to the token service</param>
/// <param name="Q">Signed masked point returned from the token service</param>
/// <param name="c">Claimed challenge from the Chaum-Pedersen proof</param>
/// <param name="z">Response from the Chaum-Pedersen proof</param>
/// <param name="r">Masking of the initial point</param>
/// <returns>A randomised signature W on the point chosen by the initiator</returns>
public ECPoint RandomiseToken(X9ECParameters ecParameters, ECPoint P, ECPoint Q, BigInteger c, BigInteger z, BigInteger r)
public ECPoint RandomiseToken(X9ECParameters ecParameters, ECPublicKeyParameters K, ECPoint P, ECPoint Q, BigInteger c, BigInteger z, BigInteger r)
{
var curve = ecParameters.Curve;
ECCurve? curve = ecParameters.Curve;

// Check that P is a valid point on the currect curve
if (ECPointVerifier.PointIsValid(P, curve) == false)
throw new AnonymousTokensException("P is not a valid point on the curve");

// Check that Q is a valid point on the currect curve
if (ECPointVerifier.PointIsValid(Q, curve) == false)
throw new Exception("Q is not a valid point on the curve");
throw new AnonymousTokensException("Q is not a valid point on the curve");

// Verify the proof (c,z).
if (!VerifyProof(ecParameters, P, Q, c, z))
{
throw new Exception("Chaum-Pedersen proof invalid.");
}
if (!VerifyProof(ecParameters, K, P, Q, c, z))
throw new AnonymousTokensException("Chaum-Pedersen proof is invalid");

// Removing the initial mask r. W = (1/r)*Q = k*T.
var rInverse = r.ModInverse(ecParameters.Curve.Order);
var W = Q.Multiply(rInverse);
BigInteger? rInverse = r.ModInverse(ecParameters.Curve.Order);
ECPoint? W = Q.Multiply(rInverse);
return W;
}
}
Expand Down
30 changes: 16 additions & 14 deletions src/AnonymousTokens.Server/Protocol/TokenGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@

using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Security;

using System;

using ECPoint = Org.BouncyCastle.Math.EC.ECPoint;

namespace AnonymousTokens.Server.Protocol
Expand All @@ -20,6 +19,13 @@ public interface ITokenGenerator

public class TokenGenerator : ITokenGenerator
{
private readonly SecureRandom _random;

public TokenGenerator()
{
_random = new SecureRandom();
}

/// <summary>
/// Used by the token service. Signs the point submitted by the initiator in order to create a token, and outputs a proof of validity.
/// </summary>
Expand All @@ -34,17 +40,17 @@ public class TokenGenerator : ITokenGenerator
X9ECParameters ecParameters,
ECPoint P)
{
var curve = ecParameters.Curve;
ECCurve? curve = ecParameters.Curve;

// Check that P is a valid point on the currect curve
if (ECPointVerifier.PointIsValid(P, curve) == false)
throw new Exception("P is not a valid point on the curve");
throw new AnonymousTokensException("P is not a valid point on the curve");

// Compute Q = k*P
var Q = P.Multiply(k);
ECPoint? Q = P.Multiply(k);

// Chaum-Pedersen proof of correct signature
var (c, z) = CreateProof(k, K, ecParameters, P, Q);
var (c, z) = CreateProof(ecParameters, k, K, P, Q);

return (Q, c, z);
}
Expand All @@ -53,23 +59,21 @@ public class TokenGenerator : ITokenGenerator
/// Used by the token service. Creates a full transcript of a Chaum-Pedersen protocol instance, using the strong Fiat-Shamir transform.
/// The Chaum-Pedersen proof proves that the same secret key k is used to compute K = k*G and Q = k*P, without revealing k.
/// </summary>
/// <param name="k">The private key.</param>
/// <param name="K">The public key.</param>
/// <param name="ecParameters">Curve parameters</param>
/// <param name="k">The private key of the token scheme</param>
/// <param name="K">The public key of the token scheme</param>
/// <param name="P">Point submitted by the initiator</param>
/// <param name="Q">Point signed using the secret key</param>
/// <returns></returns>
private (BigInteger c, BigInteger z) CreateProof(
X9ECParameters ecParameters,
BigInteger k,
ECPoint K,
X9ECParameters ecParameters,
ECPoint P,
ECPoint Q)
{
var random = new SecureRandom();

// Sample a random integer 0 < r < N
BigInteger r = ECCurveRandomNumberGenerator.GenerateRandomNumber(ecParameters.Curve, random);
BigInteger r = ECCurveRandomNumberGenerator.GenerateRandomNumber(ecParameters.Curve, _random);

// Computes X = r*G
ECPoint X = ecParameters.G.Multiply(r);
Expand All @@ -84,7 +88,5 @@ public class TokenGenerator : ITokenGenerator

return (c, z);
}


}
}
9 changes: 7 additions & 2 deletions src/AnonymousTokens.Server/Protocol/TokenVerifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,18 @@ public TokenVerifier(ISeedStore seedStore)
if (await _seedStore.ExistsAsync(t))
return false;

// Check that W is a valid point on the currect curve
if (ECPointVerifier.PointIsValid(W, curve) == false)
throw new AnonymousTokensException("W is not a valid point on the curve");

await _seedStore.SaveAsync(t);

var T = ECCurveHash.HashToWeierstrassCurve(curve, t);
ECPoint? T = ECCurveHash.HashToWeierstrassCurve(curve, t);
if (T == null)
return false;

var V = T.Multiply(k);
ECPoint? V = T.Multiply(k);

return V.Equals(W);
}
}
Expand Down
26 changes: 26 additions & 0 deletions src/AnonymousTokens/AnonymousTokensException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;

namespace AnonymousTokens
{
public class AnonymousTokensException
: Exception
{
public AnonymousTokensException()
: base()
{
}

public AnonymousTokensException(
string message)
: base(message)
{
}

public AnonymousTokensException(
string message,
Exception exception)
: base(message, exception)
{
}
}
}

0 comments on commit ca5262a

Please sign in to comment.