Skip to content

Commit

Permalink
Merge branch 'develop' into 'master'
Browse files Browse the repository at this point in the history
Develop

See merge request company-projects/Meadow!54
  • Loading branch information
Xenomega committed Oct 19, 2018
2 parents af1d019 + 4a087c8 commit 73ed06b
Show file tree
Hide file tree
Showing 57 changed files with 2,080 additions and 94 deletions.
2 changes: 1 addition & 1 deletion src/Meadow.Contract.Test/Meadow.Contract.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
Expand Down
78 changes: 78 additions & 0 deletions src/Meadow.Core.Test/Bn128Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using Meadow.Core.Cryptography.ECDSA.Bn128;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using Xunit;

namespace Meadow.Core.Test
{
/*
* Tests ported from: https://github.com/ethereum/py_ecc
* */
public class Bn128Tests
{
[Fact]
public void TestFp()
{
Assert.Equal(new Fp(4), new Fp(2) * new Fp(2));
Assert.Equal(new Fp(11) / new Fp(7), (new Fp(2) / new Fp(7)) + (new Fp(9) / new Fp(7)));
Assert.Equal(new Fp(11) * new Fp(7), (new Fp(2) * new Fp(7)) + (new Fp(9) * new Fp(7)));
Assert.Equal(new Fp(9), new Fp(9).Pow(Bn128Curve.P));
}

[Fact]
public void TestFp2()
{
Fp2 x = new Fp2(1, 0);
Fp2 f = new Fp2(1, 2);
Fp2 fpx = new Fp2(2, 2);

Assert.Equal(fpx, x + f);
Assert.Equal(Fp2.OneValue, f / f);
Assert.Equal((Fp2.OneValue + x) / f, (Fp2.OneValue / f) + (x / f));
Assert.Equal((Fp2.OneValue + x) * f, (Fp2.OneValue * f) + (x * f));
}

[Fact]
public void TestFp12()
{
Fp12 x = new Fp12(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); ;
Fp12 f = new Fp12(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
Fp12 fpx = new Fp12(2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);

Assert.Equal(fpx, x + f);
Assert.Equal(Fp12.OneValue, f / f);
Assert.Equal((Fp12.OneValue + x) / f, (Fp12.OneValue / f) + (x / f));
Assert.Equal((Fp12.OneValue + x) * f, (Fp12.OneValue * f) + (x * f));
}

[Fact]
public void TestPairing()
{
var standardResult = Bn128Pairing.Pair(Bn128Curve.G2, Bn128Curve.G1);
var negativeG1Result = Bn128Pairing.Pair(Bn128Curve.G2, Bn128Curve.G1.Negate());
Assert.Equal(Fp12.OneValue, standardResult * negativeG1Result);

var negativeG2Result = Bn128Pairing.Pair(Bn128Curve.G2.Negate(), Bn128Curve.G1);
Assert.Equal(Fp12.OneValue, standardResult * negativeG1Result);

Assert.Equal(Fp12.OneValue, standardResult.Pow(Bn128Curve.N));

var twoTimesG1Result = Bn128Pairing.Pair(Bn128Curve.G2, Bn128Curve.G1.Multiply(2));
Assert.Equal(standardResult * standardResult, twoTimesG1Result);

Assert.NotEqual(standardResult, twoTimesG1Result);
Assert.NotEqual(standardResult, negativeG2Result);
Assert.NotEqual(twoTimesG1Result, negativeG2Result);

var twoTimesG2Result = Bn128Pairing.Pair(Bn128Curve.G2.Multiply(2), Bn128Curve.G1);
Assert.Equal(standardResult * standardResult, twoTimesG2Result);

var final1 = Bn128Pairing.Pair(Bn128Curve.G2.Multiply(27), Bn128Curve.G1.Multiply(37));
var final2 = Bn128Pairing.Pair(Bn128Curve.G2, Bn128Curve.G1.Multiply(999));
Assert.Equal(final1, final2);
}
}
}
2 changes: 1 addition & 1 deletion src/Meadow.Core.Test/Meadow.Core.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
Expand Down
90 changes: 90 additions & 0 deletions src/Meadow.Core/Cryptography/ECDSA/Bn128/Bn128Curve.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Numerics;
using System.Text;

namespace Meadow.Core.Cryptography.ECDSA.Bn128
{
/// <summary>
/// Provides information about the Barreto-Naehrig curve Bn128.
/// </summary>
public abstract class Bn128Curve
{
#region Fields
private static Fp12 _twistPoint;
#endregion

#region Properties
/// <summary>
/// The elliptic curve order of the bn128 curve. This is a number which when multiplied to any other point, yields the point at infinity.
/// </summary>
public static BigInteger N { get; }
/// <summary>
/// The prime used for our field operations. Referred to as p in F_p. Used as the modulo divisor to wrap values around the field.
/// </summary>
public static BigInteger P { get; }

/// <summary>
/// Generator for curve over FQ
/// </summary>
public static FpVector3<Fp> G1 { get; }
/// <summary>
/// Generator for curve over FQ2
/// </summary>
public static FpVector3<Fp2> G2 { get; }
public static Fp B { get; }
public static Fp2 B2 { get; }
public static Fp12 B12 { get; }
#endregion

#region Constructor
/// <summary>
/// Our default static constructor, sets static read only variables.
/// </summary>
static Bn128Curve()
{
N = BigInteger.Parse("21888242871839275222246405745257275088548364400416034343698204186575808495617", CultureInfo.InvariantCulture);
P = BigInteger.Parse("21888242871839275222246405745257275088696311157297823662689037894645226208583", CultureInfo.InvariantCulture);
_twistPoint = new Fp12(0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
G1 = new FpVector3<Fp>(Fp.OneValue, new Fp(2), Fp.OneValue);
G2 = new FpVector3<Fp2>(
new Fp2(
BigInteger.Parse("10857046999023057135944570762232829481370756359578518086990519993285655852781", CultureInfo.InvariantCulture),
BigInteger.Parse("11559732032986387107991004021392285783925812861821192530917403151452391805634", CultureInfo.InvariantCulture)),
new Fp2(
BigInteger.Parse("8495653923123431417604973247489272438418190587263600148770280649306958101930", CultureInfo.InvariantCulture),
BigInteger.Parse("4082367875863433681332203403145435568316851327593401208105741076214120093531", CultureInfo.InvariantCulture)),
Fp2.OneValue);
B = new Fp(3);
B2 = new Fp2(3, 0) / new Fp2(9, 1);
B12 = new Fp12(3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
#endregion

#region Functions
public static FpVector3<Fp12> Twist(FpVector3<Fp2> point)
{
// If the point isn't properly initialize
if (point == null)
{
return null;
}

// Place the items at the start and half way point
BigInteger[] xcoefficients = new BigInteger[12] { point.X.Coefficients.ElementAt(0) - (point.X.Coefficients.ElementAt(1) * 9), 0, 0, 0, 0, 0, point.X.Coefficients.ElementAt(1), 0, 0, 0, 0, 0 };
BigInteger[] ycoefficients = new BigInteger[12] { point.Y.Coefficients.ElementAt(0) - (point.Y.Coefficients.ElementAt(1) * 9), 0, 0, 0, 0, 0, point.Y.Coefficients.ElementAt(1), 0, 0, 0, 0, 0 };
BigInteger[] zcoefficients = new BigInteger[12] { point.Z.Coefficients.ElementAt(0) - (point.Z.Coefficients.ElementAt(1) * 9), 0, 0, 0, 0, 0, point.Z.Coefficients.ElementAt(1), 0, 0, 0, 0, 0 };

// Instantiate fp12s from the extended fp2
Fp12 newx = new Fp12(xcoefficients);
Fp12 newy = new Fp12(ycoefficients);
Fp12 newz = new Fp12(zcoefficients);

// Return a twisted point from fp2 to fp12.
return new FpVector3<Fp12>(newx * _twistPoint.Pow(2), newy * _twistPoint.Pow(3), newz);
}
#endregion
}
}
155 changes: 155 additions & 0 deletions src/Meadow.Core/Cryptography/ECDSA/Bn128/Bn128Pairing.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Numerics;
using System.Text;

/*
* Portions of code ported from: https://github.com/ethereum/py_ecc
*/

namespace Meadow.Core.Cryptography.ECDSA.Bn128
{
public abstract class Bn128Pairing
{
#region Properties
public static BigInteger AteLoopCount { get; }
public static int LogAteLoopCount { get; }
public static int[] PseudoBinaryEncoding { get; }
#endregion

#region Constructor
/// <summary>
/// Our default static constructor, sets static read only variables.
/// </summary>
static Bn128Pairing()
{
AteLoopCount = BigInteger.Parse("29793968203157093288", CultureInfo.InvariantCulture);
LogAteLoopCount = 63;
PseudoBinaryEncoding = new int[]
{
0, 0, 0, 1, 0, 1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0,
0, 1, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 0, 0, 1, 1,
1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 1,
1, 0, 0, -1, 0, 0, 0, 1, 1, 0, -1, 0, 0, 1, 0, 1,
1,
};
}
#endregion

#region Functions
private static (Fp12 numerator, Fp12 denominator) LineFunction(FpVector3<Fp12> p1, FpVector3<Fp12> p2, FpVector3<Fp12> t)
{
// As mentioned in py_ecc: the projective coordinates given are (x / z, y / z).
// For slope of a line m, we usually have delta_y / delta_x. In this case it would be
// m = ((p2.y / p2.z) - (p1.y / p1.z)) / ((p2.x / p2.z) - (p1.x / p1.z))
// So to eliminate these fractions, we multiply both numerator and denominator by p1.z * p2.z,
// which yields the values below. This only affects scale but keeps the same m result.
Fp12 slopeNumerator = (p2.Y * p1.Z) - (p1.Y * p2.Z);
Fp12 slopeDenominator = (p2.X * p1.Z) - (p1.X * p2.Z);

// Determine how to compute our data.
bool denominatorIsZero = slopeDenominator == Fp12.ZeroValue;
bool numeratorIsZero = slopeNumerator == Fp12.ZeroValue;
if (denominatorIsZero && !numeratorIsZero)
{
// Slope is undefined.
return ((t.X * p1.Z) - (p1.X * t.Z), p1.Z * t.Z);
}
else if (numeratorIsZero)
{
slopeNumerator = 3 * p1.X * p1.X;
slopeDenominator = 2 * p1.Y * p1.Z;
}

Fp12 resultNumerator = (slopeNumerator * ((t.X * p1.Z) - (p1.X * t.Z))) - (slopeDenominator * ((t.Y * p1.Z) - (p1.Y * t.Z)));
Fp12 resultDenominator = slopeDenominator * t.Z * p1.Z;
return (resultNumerator, resultDenominator);
}

private static Fp12 MillerLoop(FpVector3<Fp12> q, FpVector3<Fp12> p, bool finalExponentiate = true)
{
if (q == null || p == null)
{
return Fp12.OneValue;
}

FpVector3<Fp12> nq = q.Negate();

FpVector3<Fp12> r = (FpVector3<Fp12>)q.Clone();
Fp12 fNumerator = Fp12.OneValue;
Fp12 fDenominator = Fp12.OneValue;
for (int i = LogAteLoopCount; i >= 0; i--)
{
(Fp12 num, Fp12 denom) = LineFunction(r, r, p);
fNumerator = fNumerator * fNumerator * num;
fDenominator = fDenominator * fDenominator * denom;
r = r.Double();

int v = PseudoBinaryEncoding[i];
if (v == 1)
{
(num, denom) = LineFunction(r, q, p);
fNumerator *= num;
fDenominator *= denom;
r = r.Add(q);
}
else if (v == -1)
{
(num, denom) = LineFunction(r, nq, p);
fNumerator *= num;
fDenominator *= denom;
r = r.Add(nq);
}
}

FpVector3<Fp12> q1 = new FpVector3<Fp12>(q.X.Pow(Bn128Curve.P), q.Y.Pow(Bn128Curve.P), q.Z.Pow(Bn128Curve.P));
FpVector3<Fp12> nq2 = new FpVector3<Fp12>(q1.X.Pow(Bn128Curve.P), -q1.Y.Pow(Bn128Curve.P), q1.Z.Pow(Bn128Curve.P));

(Fp12 num1, Fp12 denom1) = LineFunction(r, q1, p);
r = r.Add(q1);
(Fp12 num2, Fp12 denom2) = LineFunction(r, nq2, p);
Fp12 f = (fNumerator * num1 * num2) / (fDenominator * denom1 * denom2);

return finalExponentiate ? FinalExponentiate(f) : f;
}

public static Fp12 Pair(FpVector3<Fp2> q, FpVector3<Fp> p, bool finalExponentiate = true)
{
// Check z's for zero.
if (p.Z == Fp.ZeroValue || q.Z == Fp2.ZeroValue)
{
return Fp12.OneValue;
}

// Run the miller loop on twist(q) and fq12(p)
return MillerLoop(Bn128Curve.Twist(q), CastFpPointToFp12Point(p), finalExponentiate);
}

public static Fp12 FinalExponentiate(Fp12 p)
{
return p.Pow((BigInteger.Pow(Bn128Curve.P, 12) - 1) / Bn128Curve.N);
}

private static FpVector3<Fp12> CastFpPointToFp12Point(FpVector3<Fp> point)
{
// If our point isn't initialized, return null.
if (point == null)
{
return null;
}

// Create our data for our fq
BigInteger[] xData = new BigInteger[12];
xData[0] = point.X.N;
BigInteger[] yData = new BigInteger[12];
yData[0] = point.Y.N;
BigInteger[] zData = new BigInteger[12];
zData[0] = point.Z.N;

// Return our Fp12 vector.
return new FpVector3<Fp12>(new Fp12(xData), new Fp12(yData), new Fp12(zData));
}
#endregion
}
}

0 comments on commit 73ed06b

Please sign in to comment.