Skip to content
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
85 changes: 33 additions & 52 deletions exercises/diffie-hellman/DiffieHellmanTest.cs
Original file line number Diff line number Diff line change
@@ -1,78 +1,59 @@
using System.Linq;
// This file was auto-generated based on version 1.0.0 of the canonical data.

using System.Linq;
using System.Numerics;
using Xunit;

public class DiffieHellmanTest
{
[Fact]
public void Private_key_in_range()
public void Private_key_is_in_range_1_p()
{
var primeP = new BigInteger(23);
var privateKeys = Enumerable.Range(0, 10).Select(_ => DiffieHellman.PrivateKey(primeP)).ToList();
Assert.All(privateKeys, privateKey =>
var p = new BigInteger(7919);
var privateKeys = Enumerable.Range(0, 10).Select(_ => DiffieHellman.PrivateKey(p)).ToArray();
foreach (var privateKey in privateKeys)
{
Assert.InRange(privateKey, new BigInteger(1), primeP - new BigInteger(1));
});
}

// Note: due to the nature of randomness, there is always a chance that this test fails
// Be sure to check the actual generated values
[Fact(Skip = "Remove to run test")]
public void Private_key_randomly_generated()
{
var primeP = new BigInteger(7919);
var privateKeys = Enumerable.Range(0, 5).Select(_ => DiffieHellman.PrivateKey(primeP)).ToList();
Assert.Equal(privateKeys.Distinct().Count(), privateKeys.Count);
Assert.InRange(privateKey, new BigInteger(1), p);
}
}

[Fact(Skip = "Remove to run test")]
public void Public_key_correctly_calculated()
public void Private_key_is_random()
{
var primeP = new BigInteger(23);
var primeG = new BigInteger(5);
var privateKey = new BigInteger(6);

var actual = DiffieHellman.PublicKey(primeP, primeG, privateKey);
Assert.Equal(new BigInteger(8), actual);
var p = new BigInteger(7919);
var privateKeys = Enumerable.Range(0, 10).Select(_ => DiffieHellman.PrivateKey(p)).ToArray();
Assert.Equal(privateKeys.Distinct().Count(), privateKeys.Length);
}

[Fact(Skip = "Remove to run test")]
public void Secret_key_correctly_calculated()
public void Can_calculate_public_key_using_private_key()
{
var primeP = new BigInteger(23);
var publicKey = new BigInteger(19);
var p = new BigInteger(23);
var g = new BigInteger(5);
var privateKey = new BigInteger(6);

var actual = DiffieHellman.Secret(primeP, publicKey, privateKey);
Assert.Equal(new BigInteger(2), actual);
Assert.Equal(new BigInteger(8), DiffieHellman.PublicKey(p, g, privateKey));
}

[Fact(Skip = "Remove to run test")]
public void Secret_key_correctly_calculated_when_using_large_primes()
public void Can_calculate_secret_using_other_partys_public_key()
{
var primeP = BigInteger.Parse("120227323036150778550155526710966921740030662694578947298423549235265759593711587341037426347114541533006628856300552706996143592240453345642869233562886752930249953227657883929905072620233073626594386072962776144691433658814261874113232461749035425712805067202910389407991986070558964461330091797026762932543");
var publicKey = BigInteger.Parse("75205441154357919442925546169208711235485855904969178206313309299205868312399046149367516336607966149689640419216591714331722664409474612463910928128055994157922930443733535659848264364106037925315974095321112757711756912144137705613776063541350548911512715512539186192176020596861210448363099541947258202188");
var privateKey = BigInteger.Parse("2483479393625932939911081304356888505153797135447327501792696199190469015215177630758617902200417377685436170904594686456961202706692908603181062371925882");
var expected = BigInteger.Parse("70900735223964890815905879227737819348808518698920446491346508980461201746567735331455825644429877946556431095820785835497384849778344216981228226252639932672153547963980483673419756271345828771971984887453014488572245819864454136618980914729839523581263886740821363010486083940557620831348661126601106717071");
var actual = DiffieHellman.Secret(primeP, publicKey, privateKey);
Assert.Equal(expected, actual);
var p = new BigInteger(23);
var theirPublicKey = new BigInteger(19);
var myPrivateKey = new BigInteger(6);
Assert.Equal(new BigInteger(2), DiffieHellman.Secret(p, theirPublicKey, myPrivateKey));
}

[Fact(Skip = "Remove to run test")]
public void Test_exchange()
public void Key_exchange()
{
var primeP = new BigInteger(23);
var primeG = new BigInteger(5);

var privateKeyA = DiffieHellman.PrivateKey(primeP);
var privateKeyB = DiffieHellman.PrivateKey(primeP);

var publicKeyA = DiffieHellman.PublicKey(primeP, primeG, privateKeyA);
var publicKeyB = DiffieHellman.PublicKey(primeP, primeG, privateKeyB);

var secretA = DiffieHellman.Secret(primeP, publicKeyB, privateKeyA);
var secretB = DiffieHellman.Secret(primeP, publicKeyA, privateKeyB);

Assert.Equal(secretB, secretA);
var p = new BigInteger(23);
var g = new BigInteger(5);
var alicePrivateKey = DiffieHellman.PrivateKey(p);
var bobPrivateKey = DiffieHellman.PrivateKey(p);
var alicePublicKey = DiffieHellman.PublicKey(p, g, alicePrivateKey);
var bobPublicKey = DiffieHellman.PublicKey(p, g, bobPrivateKey);
var secretA = DiffieHellman.Secret(p, bobPublicKey, alicePrivateKey);
var secretB = DiffieHellman.Secret(p, alicePublicKey, bobPrivateKey);
Assert.Equal(secretA, secretB);
}
}
}
124 changes: 124 additions & 0 deletions generators/Exercises/Generators/DiffieHellman.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using Exercism.CSharp.Output;
using Exercism.CSharp.Output.Rendering;
using Humanizer;

namespace Exercism.CSharp.Exercises.Generators
{
public class DiffieHellman : GeneratorExercise
{
protected override void UpdateTestMethod(TestMethod testMethod)
{
switch (testMethod.Property)
{
case "privateKeyIsInRange":
UpdateTestMethodForPrivateKeyIsInRangeProperty(testMethod);
break;
case "privateKeyIsRandom":
UpdateTestMethodForPrivateKeyIsRandomProperty(testMethod);
break;
case "keyExchange":
UpdateTestMethodForKeyExchangeProperty(testMethod);
break;
default:
UpdateTestMethodForNormalProperty(testMethod);
break;
}
}

private void UpdateTestMethodForPrivateKeyIsInRangeProperty(TestMethod testMethod)
{
testMethod.TestedMethod = "PrivateKey";
testMethod.Expected["greaterThan"] = new BigInteger(testMethod.Expected["greaterThan"]);

testMethod.Arrange = RenderArrangeForPrivateKeyIsInRangeProperty(testMethod);
testMethod.Assert = RenderAssertForPrivateKeyIsInRangeProperty(testMethod);
}

private string RenderArrangeForPrivateKeyIsInRangeProperty(TestMethod testMethod)
=> RenderRandomPrivateKeysArrange(testMethod);

private string RenderAssertForPrivateKeyIsInRangeProperty(TestMethod testMethod)
{
var arrange = new StringBuilder();

arrange.AppendLine("foreach (var privateKey in privateKeys)");
arrange.AppendLine("{");
arrange.AppendLine(((string)Render.AssertInRange("privateKey", Render.Object(testMethod.Expected["greaterThan"]), "p")).Indent());
arrange.AppendLine("}");

return arrange.ToString();
}

private void UpdateTestMethodForPrivateKeyIsRandomProperty(TestMethod testMethod)
{
testMethod.TestedMethod = "PrivateKey";
testMethod.Arrange = RenderArrangeForPrivateKeyIsRandomProperty(testMethod);
testMethod.Assert = RenderAssertForPrivateKeyIsRandomProperty();
}

private string RenderArrangeForPrivateKeyIsRandomProperty(TestMethod testMethod)
=> RenderRandomPrivateKeysArrange(testMethod);

private string RenderAssertForPrivateKeyIsRandomProperty()
=> Render.AssertEqual("privateKeys.Distinct().Count()", "privateKeys.Length");

private string RenderRandomPrivateKeysArrange(TestMethod testMethod)
{
var arrange = new StringBuilder();

arrange.AppendLine(Render.Variable("p", Render.BigInteger(new BigInteger(7919))));
arrange.AppendLine(Render.Variable("privateKeys", $"Enumerable.Range(0, 10).Select(_ => {testMethod.TestedClass}.{testMethod.TestedMethod}(p)).ToArray()"));

return arrange.ToString();
}

private void UpdateTestMethodForKeyExchangeProperty(TestMethod testMethod)
{
testMethod.UseVariablesForInput = true;

var keys = testMethod.Input.Keys.ToArray();

foreach (var key in keys)
testMethod.Input[key] = ConvertKeyExchangeInput(testMethod.Input[key], testMethod);

testMethod.Assert = RenderAssertForKeyExchangeProperty();
}

private static dynamic ConvertKeyExchangeInput(dynamic input, TestMethod testMethod)
{
switch (input)
{
case long l:
return new BigInteger(l);
case string str:
return new UnescapedValue($"{testMethod.TestedClass}.{str.Pascalize()}");
default:
return input;
}
}

private string RenderAssertForKeyExchangeProperty() => Render.AssertEqual("secretA", "secretB");

private static void UpdateTestMethodForNormalProperty(TestMethod testMethod)
{
testMethod.UseVariablesForInput = true;
testMethod.Expected = new BigInteger(testMethod.Expected);

var keys = testMethod.Input.Keys.ToArray();

foreach (var key in keys)
testMethod.Input[key] = new BigInteger(testMethod.Input[key]);
}

protected override void UpdateNamespaces(ISet<string> namespaces)
{
namespaces.Add(typeof(BigInteger).Namespace);
namespaces.Add(typeof(Enumerable).Namespace);
}
}
}
2 changes: 2 additions & 0 deletions generators/Output/Rendering/Render.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text.RegularExpressions;

namespace Exercism.CSharp.Output.Rendering
Expand All @@ -23,6 +24,7 @@ public string Object(object val)
case char c: return Char(c);
case DateTime dateTime: return DateTime(dateTime);
case Regex regex: return Regex(regex);
case BigInteger bigInt: return BigInteger(bigInt);
default:
if (IsList(val))
return List((dynamic)val);
Expand Down
3 changes: 3 additions & 0 deletions generators/Output/Rendering/RenderAssert.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ public string AssertBoolean(bool expected, string actual)
public string AssertMatches(string expected, string actual)
=> RenderTemplate("AssertMatches", new { expected, actual });

public string AssertInRange(string expected, string lower, string upper)
=> RenderTemplate("AssertInRange", new { expected, lower, upper });

public string AssertThrows(Type expectedException, string actual)
=> RenderTemplate("AssertThrows", new { expected = expectedException.Name, actual });

Expand Down
3 changes: 3 additions & 0 deletions generators/Output/Rendering/RenderNumber.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Globalization;
using System.Numerics;

namespace Exercism.CSharp.Output.Rendering
{
Expand All @@ -13,5 +14,7 @@ public partial class Render
public string Ulong(ulong ulng) => $"{ulng}UL";

public string Uint(uint ui) => string.Format("0x{0:X}u", ui);

public string BigInteger(BigInteger bigInt) => $"new BigInteger({bigInt.ToString()})";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Assert.InRange({{ expected }}, {{ lower }}, {{ upper }});