First Commit
commit
c885719c5b
|
@ -0,0 +1,40 @@
|
|||
# Autosave files
|
||||
*~
|
||||
|
||||
# build
|
||||
[Oo]bj/
|
||||
[Bb]in/
|
||||
packages/
|
||||
TestResults/
|
||||
|
||||
# globs
|
||||
Makefile.in
|
||||
*.DS_Store
|
||||
*.sln.cache
|
||||
*.suo
|
||||
*.cache
|
||||
*.pidb
|
||||
*.userprefs
|
||||
*.usertasks
|
||||
config.log
|
||||
config.make
|
||||
config.status
|
||||
aclocal.m4
|
||||
install-sh
|
||||
autom4te.cache/
|
||||
*.user
|
||||
*.tar.gz
|
||||
tarballs/
|
||||
test-results/
|
||||
Thumbs.db
|
||||
|
||||
# Mac bundle stuff
|
||||
*.dmg
|
||||
*.app
|
||||
|
||||
# resharper
|
||||
*_Resharper.*
|
||||
*.Resharper
|
||||
|
||||
# dotCover
|
||||
*.dotCover
|
|
@ -0,0 +1,48 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26124.0
|
||||
MinimumVisualStudioVersion = 15.0.26124.0
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.crypto.ec", "ln.crypto.ec\ln.crypto.ec.csproj", "{4D57CD8B-AA87-47E3-A7CC-01E9C5DF7E28}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.crypto.ec.test", "ln.crypto.ec.test\ln.crypto.ec.test.csproj", "{83A9ED0C-94F6-4E45-AA3C-D39DE427A13C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{4D57CD8B-AA87-47E3-A7CC-01E9C5DF7E28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4D57CD8B-AA87-47E3-A7CC-01E9C5DF7E28}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4D57CD8B-AA87-47E3-A7CC-01E9C5DF7E28}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{4D57CD8B-AA87-47E3-A7CC-01E9C5DF7E28}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{4D57CD8B-AA87-47E3-A7CC-01E9C5DF7E28}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{4D57CD8B-AA87-47E3-A7CC-01E9C5DF7E28}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{4D57CD8B-AA87-47E3-A7CC-01E9C5DF7E28}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4D57CD8B-AA87-47E3-A7CC-01E9C5DF7E28}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4D57CD8B-AA87-47E3-A7CC-01E9C5DF7E28}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{4D57CD8B-AA87-47E3-A7CC-01E9C5DF7E28}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4D57CD8B-AA87-47E3-A7CC-01E9C5DF7E28}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{4D57CD8B-AA87-47E3-A7CC-01E9C5DF7E28}.Release|x86.Build.0 = Release|Any CPU
|
||||
{83A9ED0C-94F6-4E45-AA3C-D39DE427A13C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{83A9ED0C-94F6-4E45-AA3C-D39DE427A13C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{83A9ED0C-94F6-4E45-AA3C-D39DE427A13C}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{83A9ED0C-94F6-4E45-AA3C-D39DE427A13C}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{83A9ED0C-94F6-4E45-AA3C-D39DE427A13C}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{83A9ED0C-94F6-4E45-AA3C-D39DE427A13C}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{83A9ED0C-94F6-4E45-AA3C-D39DE427A13C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{83A9ED0C-94F6-4E45-AA3C-D39DE427A13C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{83A9ED0C-94F6-4E45-AA3C-D39DE427A13C}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{83A9ED0C-94F6-4E45-AA3C-D39DE427A13C}.Release|x64.Build.0 = Release|Any CPU
|
||||
{83A9ED0C-94F6-4E45-AA3C-D39DE427A13C}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{83A9ED0C-94F6-4E45-AA3C-D39DE427A13C}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,224 @@
|
|||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Crypto.EC;
|
||||
using ln.crypto.ec.lsag;
|
||||
using NUnit.Framework;
|
||||
using System.Numerics;
|
||||
using System.Globalization;
|
||||
|
||||
namespace ln.crypto.ec.test
|
||||
{
|
||||
public class Tests
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_05_BigInteger()
|
||||
{
|
||||
foreach (TestVector testVector in vectors)
|
||||
{
|
||||
BigInteger bi = BigInteger.Parse(testVector.sx, System.Globalization.NumberStyles.HexNumber);
|
||||
string si = bi.ToString("X");
|
||||
BigInteger bi2 = BigInteger.Parse(si, System.Globalization.NumberStyles.HexNumber);
|
||||
|
||||
TestContext.Error.WriteLine("BigInteger Test: SRC={0}", bi.ToString("X"));
|
||||
TestContext.Error.WriteLine("BigInteger Test: DST={0}", bi2.ToString("X"));
|
||||
Assert.IsTrue(bi == bi2);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_10_Curve()
|
||||
{
|
||||
EllipticCurve secp256k1 = EllipticCurve.createSecp256k1();
|
||||
|
||||
/* Minimum check security... TODO: */
|
||||
Assert.IsFalse(new CurvePoint(secp256k1, 4, 3).isOnCurve());
|
||||
|
||||
|
||||
foreach (TestVector testVector in vectors)
|
||||
{
|
||||
TestContext.Error.WriteLine("TestCurve: k={0}", testVector.k);
|
||||
|
||||
CurvePoint testPoint = new CurvePoint(secp256k1, testVector.x, testVector.y);
|
||||
CurvePoint checkPoint = secp256k1.G * testVector.k;
|
||||
|
||||
if (!Object.Equals(checkPoint, testPoint))
|
||||
{
|
||||
TestContext.Error.WriteLine("TestCurve: modulus: {0}", secp256k1.Fp.FieldModulo.ToString("X"));
|
||||
TestContext.Error.WriteLine("TestCurve: test x: {0}", testPoint.X.ToString("X"));
|
||||
TestContext.Error.WriteLine("TestCurve: test y: {0}", testPoint.Y.ToString("X"));
|
||||
TestContext.Error.WriteLine("TestCurve: check x: {0}", checkPoint.X.ToString("X"));
|
||||
TestContext.Error.WriteLine("TestCurve: check y: {0}", checkPoint.Y.ToString("X"));
|
||||
}
|
||||
Assert.AreEqual(testPoint, checkPoint);
|
||||
Assert.IsTrue( checkPoint.isOnCurve() );
|
||||
}
|
||||
|
||||
|
||||
Assert.Pass();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_11_Performance_Point_Mul()
|
||||
{
|
||||
int testCount = 2000;
|
||||
BigInteger n = BigInteger.Parse("115792089237316195423570985008687907852837564279074904382605163141518161494317", NumberStyles.HexNumber);
|
||||
CurvePoint G = EllipticCurve.SECP256K1.G;
|
||||
CurvePoint result = null;
|
||||
|
||||
DateTime start = DateTime.Now;
|
||||
|
||||
for (int i=0; i<testCount; i++)
|
||||
{
|
||||
result = G * n;
|
||||
}
|
||||
|
||||
DateTime stop = DateTime.Now;
|
||||
TestContext.Error.WriteLine("Point Multiplication Performance: needed {0}ms ( {1} multiplications / s )", (stop - start).TotalMilliseconds, (testCount * 1000) / (stop - start).TotalMilliseconds);
|
||||
TestContext.Error.WriteLine("Resulting Point is: {0}", result.toHexString());
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void Test_15_GenerateKeyPairs()
|
||||
{
|
||||
RandomNumberGenerator random = RandomNumberGenerator.Create();
|
||||
|
||||
for (int i=0; i< 10; i++)
|
||||
{
|
||||
byte[] random32 = new byte[32];
|
||||
random.GetBytes(random32);
|
||||
BigInteger privkey = EllipticCurve.SECP256K1.Fp.Fit(new BigInteger(random32));
|
||||
CurvePoint publicKey = EllipticCurve.SECP256K1.G * privkey;
|
||||
|
||||
TestContext.Error.WriteLine("Generated Key-Pair: {0} : {1}", privkey.ToString("X"), publicKey.toHex());
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_20_LSAG()
|
||||
{
|
||||
byte[] message = Encoding.UTF8.GetBytes("I am the first and only to be signed text!");
|
||||
|
||||
LSAGDoTest(3, 3, message);
|
||||
LSAGDoTest(10, 5, message);
|
||||
LSAGDoTest(100, 5, message);
|
||||
LSAGDoTest(1000, 5, message);
|
||||
|
||||
}
|
||||
|
||||
public void LSAGDoTest(int ringsize, int testsize, byte[] message)
|
||||
{
|
||||
TestContext.Error.WriteLine("LSAGDotest({0})", ringsize);
|
||||
|
||||
RandomNumberGenerator random = RandomNumberGenerator.Create();
|
||||
|
||||
BigInteger[] privateKeys = new BigInteger[ringsize];
|
||||
CurvePoint[] publicKeys = new CurvePoint[ringsize];
|
||||
|
||||
byte[] random32 = new byte[32];
|
||||
for (int n=0;n<ringsize;n++)
|
||||
{
|
||||
random.GetBytes(random32);
|
||||
privateKeys[n] = EllipticCurve.SECP256K1.Fp.Fit(new BigInteger(random32));
|
||||
publicKeys[n] = EllipticCurve.SECP256K1.G * privateKeys[n];
|
||||
}
|
||||
|
||||
LSAG.Signature[] signatures = new LSAG.Signature[ringsize];
|
||||
|
||||
DateTime start = DateTime.Now;
|
||||
|
||||
for (int n=0;n<testsize;n++)
|
||||
{
|
||||
LSAG.Sign(message, EllipticCurve.SECP256K1, privateKeys[n % privateKeys.Length], publicKeys, out signatures[n]);
|
||||
}
|
||||
|
||||
DateTime stop = DateTime.Now;
|
||||
TestContext.Error.WriteLine("LSAGDotest({0}): needed {1}ms ( {2}ms / sign )", ringsize, (stop - start).TotalMilliseconds,(stop - start).TotalMilliseconds / testsize);
|
||||
|
||||
start = DateTime.Now;
|
||||
|
||||
for (int n=0;n<testsize;n++)
|
||||
{
|
||||
Assert.IsTrue(LSAG.Verify(EllipticCurve.SECP256K1, message, publicKeys, signatures[n]));
|
||||
}
|
||||
|
||||
stop = DateTime.Now;
|
||||
|
||||
|
||||
TestContext.Error.WriteLine("LSAGDotest({0}): needed {1}ms ( {2}ms / verify )", ringsize, (stop - start).TotalMilliseconds,(stop - start).TotalMilliseconds / testsize);
|
||||
|
||||
for (int n=0;n<testsize;n++)
|
||||
{
|
||||
Assert.IsFalse(LSAG.Verify(EllipticCurve.SECP256K1, message, publicKeys, signatures[n].C0 + 1, signatures[n].s, signatures[n].Y));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
struct TestVector
|
||||
{
|
||||
public BigInteger k,x,y;
|
||||
public string sk,sx,sy;
|
||||
|
||||
public TestVector(BigInteger k, BigInteger x, BigInteger y)
|
||||
{
|
||||
this.k = k;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
this.sk = k.ToString();
|
||||
this.sx = x.ToString();
|
||||
this.sy = y.ToString();
|
||||
}
|
||||
public TestVector(string k, string x, string y)
|
||||
{
|
||||
this.k = BigInteger.Parse(k);
|
||||
this.x = BigInteger.Parse(x, NumberStyles.HexNumber);
|
||||
this.y = BigInteger.Parse(y, NumberStyles.HexNumber);
|
||||
|
||||
this.sk = k;
|
||||
this.sx = x;
|
||||
this.sy = y;
|
||||
}
|
||||
}
|
||||
|
||||
TestVector[] vectors = new TestVector[]{
|
||||
new TestVector("1","0079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798","00483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"),
|
||||
new TestVector("2","00C6047F9441ED7D6D3045406E95C07CD85C778E4B8CEF3CA7ABAC09B95C709EE5","001AE168FEA63DC339A3C58419466CEAEEF7F632653266D0E1236431A950CFE52A"),
|
||||
new TestVector("3","00F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9","00388F7B0F632DE8140FE337E62A37F3566500A99934C2231B6CB9FD7584B8E672"),
|
||||
new TestVector("4","00E493DBF1C10D80F3581E4904930B1404CC6C13900EE0758474FA94ABE8C4CD13","0051ED993EA0D455B75642E2098EA51448D967AE33BFBDFE40CFE97BDC47739922"),
|
||||
new TestVector("5","002F8BDE4D1A07209355B4A7250A5C5128E88B84BDDC619AB7CBA8D569B240EFE4","00D8AC222636E5E3D6D4DBA9DDA6C9C426F788271BAB0D6840DCA87D3AA6AC62D6"),
|
||||
new TestVector("6","00FFF97BD5755EEEA420453A14355235D382F6472F8568A18B2F057A1460297556","00AE12777AACFBB620F3BE96017F45C560DE80F0F6518FE4A03C870C36B075F297"),
|
||||
new TestVector("7","005CBDF0646E5DB4EAA398F365F2EA7A0E3D419B7E0330E39CE92BDDEDCAC4F9BC","006AEBCA40BA255960A3178D6D861A54DBA813D0B813FDE7B5A5082628087264DA"),
|
||||
new TestVector("8","002F01E5E15CCA351DAFF3843FB70F3C2F0A1BDD05E5AF888A67784EF3E10A2A01","005C4DA8A741539949293D082A132D13B4C2E213D6BA5B7617B5DA2CB76CBDE904"),
|
||||
new TestVector("9","00ACD484E2F0C7F65309AD178A9F559ABDE09796974C57E714C35F110DFC27CCBE","00CC338921B0A7D9FD64380971763B61E9ADD888A4375F8E0F05CC262AC64F9C37"),
|
||||
new TestVector("10","00A0434D9E47F3C86235477C7B1AE6AE5D3442D49B1943C2B752A68E2A47E247C7","00893ABA425419BC27A3B6C7E693A24C696F794C2ED877A1593CBEE53B037368D7"),
|
||||
new TestVector("11","00774AE7F858A9411E5EF4246B70C65AAC5649980BE5C17891BBEC17895DA008CB","00D984A032EB6B5E190243DD56D7B7B365372DB1E2DFF9D6A8301D74C9C953C61B"),
|
||||
new TestVector("12","00D01115D548E7561B15C38F004D734633687CF4419620095BC5B0F47070AFE85A","00A9F34FFDC815E0D7A8B64537E17BD81579238C5DD9A86D526B051B13F4062327"),
|
||||
new TestVector("13","00F28773C2D975288BC7D1D205C3748651B075FBC6610E58CDDEEDDF8F19405AA8","000AB0902E8D880A89758212EB65CDAF473A1A06DA521FA91F29B5CB52DB03ED81"),
|
||||
new TestVector("14","00499FDF9E895E719CFD64E67F07D38E3226AA7B63678949E6E49B241A60E823E4","00CAC2F6C4B54E855190F044E4A7B3D464464279C27A3F95BCC65F40D403A13F5B"),
|
||||
new TestVector("15","00D7924D4F7D43EA965A465AE3095FF41131E5946F3C85F79E44ADBCF8E27E080E","00581E2872A86C72A683842EC228CC6DEFEA40AF2BD896D3A5C504DC9FF6A26B58"),
|
||||
new TestVector("16","00E60FCE93B59E9EC53011AABC21C23E97B2A31369B87A5AE9C44EE89E2A6DEC0A","00F7E3507399E595929DB99F34F57937101296891E44D23F0BE1F32CCE69616821"),
|
||||
new TestVector("17","00DEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34","004211AB0694635168E997B0EAD2A93DAECED1F4A04A95C0F6CFB199F69E56EB77"),
|
||||
new TestVector("18","005601570CB47F238D2B0286DB4A990FA0F3BA28D1A319F5E7CF55C2A2444DA7CC","00C136C1DC0CBEB930E9E298043589351D81D8E0BC736AE2A1F5192E5E8B061D58"),
|
||||
new TestVector("19","002B4EA0A797A443D293EF5CFF444F4979F06ACFEBD7E86D277475656138385B6C","0085E89BC037945D93B343083B5A1C86131A01F60C50269763B570C854E5C09B7A"),
|
||||
new TestVector("20","004CE119C96E2FA357200B559B2F7DD5A5F02D5290AFF74B03F3E471B273211C97","0012BA26DCB10EC1625DA61FA10A844C676162948271D96967450288EE9233DC3A"),
|
||||
new TestVector("112233445566778899","00A90CC3D3F3E146DAADFC74CA1372207CB4B725AE708CEF713A98EDD73D99EF29","005A79D6B289610C68BC3B47F3D72F9788A26A06868B4D8E433E1E2AD76FB7DC76"),
|
||||
new TestVector("112233445566778899112233445566778899","00E5A2636BCFD412EBF36EC45B19BFB68A1BC5F8632E678132B885F7DF99C5E9B3","00736C1CE161AE27B405CAFD2A7520370153C2C861AC51D6C1D5985D9606B45F39"),
|
||||
new TestVector("28948022309329048855892746252171976963209391069768726095651290785379540373584","00A6B594B38FB3E77C6EDF78161FADE2041F4E09FD8497DB776E546C41567FEB3C","0071444009192228730CD8237A490FEBA2AFE3D27D7CC1136BC97E439D13330D55"),
|
||||
new TestVector("57896044618658097711785492504343953926418782139537452191302581570759080747168","0000000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C63","003F3979BF72AE8202983DC989AEC7F2FF2ED91BDD69CE02FC0700CA100E59DDF3"),
|
||||
new TestVector("86844066927987146567678238756515930889628173209306178286953872356138621120752","00E24CE4BEEE294AA6350FAA67512B99D388693AE4E7F53D19882A6EA169FC1CE1","008B71E83545FC2B5872589F99D948C03108D36797C4DE363EBD3FF6A9E1A95B10"),
|
||||
new TestVector("115792089237316195423570985008687907852837564279074904382605163141518161494317","004CE119C96E2FA357200B559B2F7DD5A5F02D5290AFF74B03F3E471B273211C97","00ED45D9234EF13E9DA259E05EF57BB3989E9D6B7D8E269698BAFD77106DCC1FF5"),
|
||||
new TestVector("115792089237316195423570985008687907852837564279074904382605163141518161494318","002B4EA0A797A443D293EF5CFF444F4979F06ACFEBD7E86D277475656138385B6C","007A17643FC86BA26C4CBCF7C4A5E379ECE5FE09F3AFD9689C4A8F37AA1A3F60B5"),
|
||||
new TestVector("115792089237316195423570985008687907852837564279074904382605163141518161494319","005601570CB47F238D2B0286DB4A990FA0F3BA28D1A319F5E7CF55C2A2444DA7CC","003EC93E23F34146CF161D67FBCA76CAE27E271F438C951D5E0AE6D1A074F9DED7"),
|
||||
new TestVector("115792089237316195423570985008687907852837564279074904382605163141518161494320","00DEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34","00BDEE54F96B9CAE9716684F152D56C251312E0B5FB56A3F09304E660861A910B8")
|
||||
};
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp5.0</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0"/>
|
||||
|
||||
<ProjectReference Include="../ln.crypto.ec/ln.crypto.ec.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,159 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Crypto.EC
|
||||
{
|
||||
public class CurvePoint
|
||||
{
|
||||
public static readonly CurvePoint INFINITY = new CurvePoint();
|
||||
|
||||
public CurvePoint(EllipticCurve curve,BigInteger x,BigInteger y){
|
||||
Curve = curve;
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
|
||||
private CurvePoint(){
|
||||
this.Curve = null;
|
||||
this.X = 0;
|
||||
this.Y = 0;
|
||||
}
|
||||
|
||||
public string toHexString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append(X.ToString("X"));
|
||||
sb.Append(".");
|
||||
sb.Append(Y.ToString("X"));
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string toHex()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append(X.ToString("X32"));
|
||||
sb.Append(Y.ToString("X32"));
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if ((object)this == (object)INFINITY){
|
||||
return String.Format("[CurvePoint INFINITY]");
|
||||
}
|
||||
return String.Format("[CurvePoint X={0} Y={1}]",X.ToString("X"),Y.ToString("X"));
|
||||
}
|
||||
|
||||
public EllipticCurve Curve { get; private set; }
|
||||
public BigInteger X { get; private set; }
|
||||
public BigInteger Y { get; private set; }
|
||||
|
||||
public bool isOnCurve(){
|
||||
return this.Curve.isOnCurve(this);
|
||||
}
|
||||
|
||||
public bool isInfinity(){
|
||||
return ((object)this == (object)INFINITY);
|
||||
}
|
||||
|
||||
public CurvePoint Negated(){
|
||||
return new CurvePoint(Curve, X, Curve.Fp.AdditiveInverse(Y));
|
||||
}
|
||||
|
||||
public static CurvePoint operator +(CurvePoint p1, CurvePoint p2)
|
||||
{
|
||||
if ((object)p1 == (object)INFINITY){
|
||||
return p2;
|
||||
}
|
||||
if ((object)p2 == (object)INFINITY){
|
||||
return p1;
|
||||
}
|
||||
|
||||
return p1.Curve.Add(p1, p2);
|
||||
}
|
||||
|
||||
public static CurvePoint operator -(CurvePoint p1, CurvePoint p2)
|
||||
{
|
||||
if ((object)p1 == (object)INFINITY){
|
||||
return p2;
|
||||
}
|
||||
if ((object)p2 == (object)INFINITY){
|
||||
return p1;
|
||||
}
|
||||
return p1.Curve.Add(p1, p2.Negated());
|
||||
}
|
||||
|
||||
public static CurvePoint operator *(CurvePoint p1, BigInteger n)
|
||||
{
|
||||
if ((object)p1 == (object)INFINITY){
|
||||
return INFINITY;
|
||||
}
|
||||
|
||||
if (p1.Y == BigInteger.Zero){
|
||||
return INFINITY;
|
||||
}
|
||||
|
||||
if (n.IsZero){
|
||||
throw new NotImplementedException("CurvePoint * 0");
|
||||
}
|
||||
|
||||
CurvePoint result = null;
|
||||
CurvePoint p = p1;
|
||||
|
||||
int i;
|
||||
byte[] nBytes = n.ToByteArray();
|
||||
|
||||
for (i = 0; i < nBytes.Length<<3; i++)
|
||||
{
|
||||
if ((nBytes[i >> 3] & (1 << (i & 0x07))) != 0)
|
||||
break;
|
||||
|
||||
p += p;
|
||||
}
|
||||
|
||||
result = p;
|
||||
|
||||
for (i++; i < nBytes.Length<<3; i++)
|
||||
{
|
||||
p += p;
|
||||
if ((nBytes[i >> 3] & (1 << (i & 0x07))) != 0)
|
||||
{
|
||||
result = p + result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool operator ==(CurvePoint p1, CurvePoint p2)
|
||||
{
|
||||
if ((p1 is null)||(p2 is null)){
|
||||
return false;
|
||||
}
|
||||
return (p1.X == p2.X) && (p1.Y == p2.Y);
|
||||
}
|
||||
public static bool operator !=(CurvePoint p1, CurvePoint p2)
|
||||
{
|
||||
if ((p1 is null)||(p2 is null)){
|
||||
return false;
|
||||
}
|
||||
return (p1.X != p2.X) || (p1.Y != p2.Y);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj) => (obj is CurvePoint cp2) && X.Equals(cp2.X) && Y.Equals(cp2.Y);
|
||||
public override int GetHashCode() => X.GetHashCode() ^ Y.GetHashCode();
|
||||
|
||||
public byte[] ToByteArray()
|
||||
{
|
||||
int bytesPerValue = Curve.Fp.FieldModulo.GetByteCount();
|
||||
byte[] result = new byte[bytesPerValue*2];
|
||||
X.TryWriteBytes(new Span<byte>(result, 0, bytesPerValue), out int bytesWritten);
|
||||
Y.TryWriteBytes(new Span<byte>(result, bytesPerValue, bytesPerValue), out bytesWritten);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using ln.crypto.ec;
|
||||
using System.Security.Cryptography;
|
||||
using System.Numerics;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Crypto.EC
|
||||
{
|
||||
public class EllipticCurve
|
||||
{
|
||||
public BigInteger a { get; private set; }
|
||||
public BigInteger b { get; private set; }
|
||||
public BigInteger n { get; private set; }
|
||||
public int h { get; private set; }
|
||||
|
||||
public CurvePoint G { get; private set; }
|
||||
public Field Fp { get; private set; }
|
||||
|
||||
public EllipticCurve(BigInteger p,BigInteger a,BigInteger b,BigInteger xG,BigInteger yG,BigInteger n,int h)
|
||||
{
|
||||
this.Fp = new Field(p);
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
this.n = n;
|
||||
this.h = h;
|
||||
this.G = new CurvePoint(this, xG, yG);
|
||||
|
||||
if (!isOnCurve(this.G)){
|
||||
throw new ArgumentException("G is not part of the curve");
|
||||
}
|
||||
}
|
||||
|
||||
public BigInteger Y2(BigInteger x)
|
||||
{
|
||||
BigInteger yy = BigInteger.ModPow(x, 3, Fp.FieldModulo);
|
||||
yy += (a * x);
|
||||
yy += b;
|
||||
yy %= this.Fp.FieldModulo;
|
||||
return yy;
|
||||
}
|
||||
|
||||
public bool isOnCurve(CurvePoint p){
|
||||
BigInteger py2 = BigInteger.ModPow(p.Y, 2, this.Fp.FieldModulo);
|
||||
BigInteger pcy2 = Y2(p.X);
|
||||
|
||||
//Console.WriteLine("CHECK A: {0}",py2.toHexString());
|
||||
//Console.WriteLine("CHECK B: {0}",pcy2.toHexString());
|
||||
|
||||
return (py2 == pcy2);
|
||||
}
|
||||
|
||||
public CurvePoint Add(CurvePoint p1, CurvePoint p2)
|
||||
{
|
||||
if ((p1 is null) || (p2 is null))
|
||||
{
|
||||
throw new ArgumentException("SignedCurvePoints to be added must not be null");
|
||||
}
|
||||
|
||||
if (p1.Curve != p2.Curve)
|
||||
{
|
||||
throw new ArgumentException("SignedCurvePoints to be added must belong to the same curve!");
|
||||
}
|
||||
|
||||
if ((p1 != p2) && (p1.X == p2.X)){
|
||||
return CurvePoint.INFINITY;
|
||||
}
|
||||
|
||||
BigInteger lambda,divlambda;
|
||||
|
||||
if (p1 == p2){
|
||||
lambda = Fp.Fit(3 * BigInteger.ModPow(p1.X, 2, Fp.FieldModulo) + a);
|
||||
divlambda = Fp.Fit(2 * p1.Y);
|
||||
} else {
|
||||
lambda = Fp.Fit(p2.Y - p1.Y);
|
||||
divlambda = Fp.Fit(p2.X - p1.X);
|
||||
}
|
||||
|
||||
|
||||
|
||||
lambda = lambda * Euclid.inverse(divlambda, Fp.FieldModulo);
|
||||
|
||||
BigInteger xR = (BigInteger.ModPow(lambda, 2, Fp.FieldModulo) - p1.X - p2.X);
|
||||
BigInteger yR = (lambda * (p1.X - xR)) - p1.Y;
|
||||
|
||||
xR = Fp.Fit(xR);
|
||||
yR = Fp.Fit(yR);
|
||||
|
||||
return new CurvePoint(this, xR, yR);
|
||||
}
|
||||
|
||||
public CurvePoint HashToPoint(byte[] message)
|
||||
{
|
||||
byte[] hash = SHA256.Create().ComputeHash(message);
|
||||
BigInteger bi = new BigInteger(hash) * 16;
|
||||
return MapToCurve(bi);
|
||||
}
|
||||
|
||||
public BigInteger[] HashToField(byte[] message, int n)
|
||||
{
|
||||
byte[] hash = SHA256.Create().ComputeHash(message);
|
||||
BigInteger[] results = new BigInteger[n];
|
||||
for (int i=0;i<n;i++)
|
||||
{
|
||||
hash = SHA256.Create().ComputeHash(hash);
|
||||
results[i] = Fp.Fit(new BigInteger(hash));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
public BigInteger HashToField(byte[] message) => HashToField(message, 1)[0];
|
||||
|
||||
public CurvePoint MapToCurve(BigInteger u) => G * Fp.Fit(u);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendFormat("[EllipticCurve] Fp={0}\n",(Fp == null) ? "" : Fp.ToString());
|
||||
sb.AppendFormat("[EllipticCurve] a={0}\n",a.ToString("X"));
|
||||
sb.AppendFormat("[EllipticCurve] b={0}\n",b.ToString("X"));
|
||||
sb.AppendFormat("[EllipticCurve] Gx={0}\n",G.X.ToString("X"));
|
||||
sb.AppendFormat("[EllipticCurve] Gy={0}\n",G.Y.ToString("X"));
|
||||
sb.AppendFormat("[EllipticCurve] G on curve? {0}",isOnCurve(G));
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static EllipticCurve createSecp256k1(){
|
||||
BigInteger p = (BigInteger.One << 256);
|
||||
p -= BigInteger.One;
|
||||
p -= (BigInteger.One << 32);
|
||||
p -= (BigInteger.One << 9);
|
||||
p -= (BigInteger.One << 8);
|
||||
p -= (BigInteger.One << 7);
|
||||
p -= (BigInteger.One << 6);
|
||||
p -= (BigInteger.One << 4);
|
||||
|
||||
BigInteger xG = BigInteger.Parse("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", NumberStyles.HexNumber);
|
||||
BigInteger yG = BigInteger.Parse("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", NumberStyles.HexNumber);
|
||||
|
||||
BigInteger n = BigInteger.Parse("00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", NumberStyles.HexNumber);
|
||||
return new EllipticCurve(p, BigInteger.Zero, 7, xG, yG, n, 1);
|
||||
}
|
||||
|
||||
public static readonly EllipticCurve SECP256K1 = createSecp256k1();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
|
||||
namespace ln.crypto.ec
|
||||
{
|
||||
public static class Euclid
|
||||
{
|
||||
|
||||
public static Tuple<BigInteger,BigInteger,BigInteger> extended(BigInteger a, BigInteger b)
|
||||
{
|
||||
if (b.IsZero){
|
||||
if (a != BigInteger.One){
|
||||
throw new ArgumentException("Euclid found GCD>1!");
|
||||
}
|
||||
return new Tuple<BigInteger,BigInteger,BigInteger>(a, BigInteger.One, BigInteger.Zero);
|
||||
}
|
||||
Tuple<BigInteger,BigInteger,BigInteger> r = extended(b, a % b);
|
||||
return new Tuple<BigInteger,BigInteger,BigInteger>(r.Item1,r.Item3,r.Item2 - ((a / b) * r.Item3) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of inverse() like found at
|
||||
* https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm (14 Oct 2017)
|
||||
**/
|
||||
public static BigInteger inverse(BigInteger a,BigInteger m){
|
||||
BigInteger one, zero;
|
||||
|
||||
rt act, next, future;
|
||||
|
||||
one = BigInteger.One;
|
||||
zero = BigInteger.Zero;
|
||||
|
||||
act = new rt(m, zero);
|
||||
next = new rt(a, one);
|
||||
|
||||
while (!next.r.IsZero)
|
||||
{
|
||||
BigInteger q = act.r / next.r;
|
||||
future = new rt(
|
||||
act.r - (q * next.r),
|
||||
act.t - (q * next.t)
|
||||
);
|
||||
|
||||
//Console.WriteLine("EUCLID: q = {0}",q);
|
||||
//Console.WriteLine("EUCLID: act: r = {0} / t = {1}",act.r,act.t);
|
||||
//Console.WriteLine("EUCLID: next: r = {0} / t = {1}",next.r,next.t);
|
||||
//Console.WriteLine("EUCLID: future: r = {0} / t = {1}",future.r,future.t);
|
||||
|
||||
act = next;
|
||||
next = future;
|
||||
}
|
||||
|
||||
if (act.r > one){
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
if (act.t < 0){
|
||||
act.t += m;
|
||||
}
|
||||
|
||||
return act.t;
|
||||
}
|
||||
|
||||
private struct rt {
|
||||
public BigInteger r, t;
|
||||
|
||||
public rt(BigInteger r,BigInteger t){
|
||||
this.r = r;
|
||||
this.t = t;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
|
||||
namespace ln.crypto.ec
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
|
||||
public static T[] Segment<T>(this T[] a,int start) => Segment(a, start, a.Length);
|
||||
public static T[] Segment<T>(this T[] a,int start, int length)
|
||||
{
|
||||
T[] r = new T[length];
|
||||
Array.Copy(a, start, r, 0, length > a.Length ? a.Length : length);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static byte[] GetBytes(this uint[] a)
|
||||
{
|
||||
byte[] r = new byte[a.Length * 4];
|
||||
for (int n=0;n<a.Length;n++)
|
||||
Array.Copy(BitConverter.GetBytes(a[n]),0,r,(n*4),4);
|
||||
return r;
|
||||
}
|
||||
public static byte[] GetBytes(this int[] a)
|
||||
{
|
||||
byte[] r = new byte[a.Length * 4];
|
||||
for (int n=0;n<a.Length;n++)
|
||||
Array.Copy(BitConverter.GetBytes(a[n]),0,r,(n*4),4);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static T[] Reverse<T>(T[] a)
|
||||
{
|
||||
T[] r = (T[])a.Clone();
|
||||
Array.Reverse(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static int CreateHashCode(this byte[] bytes)
|
||||
{
|
||||
int hash = 0x22447799;
|
||||
foreach (byte by in bytes)
|
||||
hash *= by;
|
||||
return hash;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
|
||||
namespace ln.crypto.ec
|
||||
{
|
||||
public class Field
|
||||
{
|
||||
public static Field Default { get; set; } = null; // new IntField(UBigInteger.ZERO.Resize(256) - 1);
|
||||
public static Field INFINITY { get; private set; } = new Field();
|
||||
|
||||
public BigInteger FieldModulo { get; private set; }
|
||||
|
||||
public Field(BigInteger p){
|
||||
this.FieldModulo = p;
|
||||
}
|
||||
|
||||
private Field(){
|
||||
this.FieldModulo = 0;
|
||||
}
|
||||
|
||||
public BigInteger Fit(BigInteger value)
|
||||
{
|
||||
if (FieldModulo.IsZero){
|
||||
return value;
|
||||
}
|
||||
|
||||
value %= FieldModulo;
|
||||
if (value.Sign < 0)
|
||||
{
|
||||
value += FieldModulo;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public BigInteger AdditiveInverse(BigInteger value){
|
||||
return FieldModulo - value;
|
||||
}
|
||||
|
||||
public override string ToString(){
|
||||
return String.Format("[IntField p={0}]",this.FieldModulo);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,198 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using ln.crypto.ec;
|
||||
|
||||
// namespace Crypto.EC
|
||||
// {
|
||||
// public class ProjectiveCurvePoint
|
||||
// {
|
||||
// public static readonly ProjectiveCurvePoint INFINITY = new ProjectiveCurvePoint(null,1,0,0);
|
||||
|
||||
// public BigInteger X { get; set; }
|
||||
// public BigInteger Y { get; set; }
|
||||
// public BigInteger Z { get; set; }
|
||||
|
||||
// public EllipticCurve Curve { get; private set; }
|
||||
|
||||
// public ProjectiveCurvePoint(CurvePoint p)
|
||||
// {
|
||||
// this.Curve = p.Curve;
|
||||
// this.X = p.X;
|
||||
// this.Y = p.Y;
|
||||
// this.Z = 1;
|
||||
// }
|
||||
|
||||
// public ProjectiveCurvePoint(EllipticCurve curve,BigInteger x,BigInteger y,BigInteger z)
|
||||
// {
|
||||
// this.Curve = curve;
|
||||
// this.X = x;
|
||||
// this.Y = y;
|
||||
// this.Z = z;
|
||||
// }
|
||||
|
||||
// public CurvePoint toCurvePoint(){
|
||||
// if (Z.IsZero){
|
||||
// return CurvePoint.INFINITY;
|
||||
// }
|
||||
// BigInteger iz = Euclid.inverse(Z, Curve.Fp.FieldModulo);
|
||||
|
||||
// BigInteger nx = Curve.Fp.Fit(X * iz);
|
||||
// BigInteger ny = Curve.Fp.Fit(Y * iz);
|
||||
|
||||
// return new CurvePoint(Curve, nx, ny);
|
||||
// }
|
||||
|
||||
// public override bool Equals(object obj)
|
||||
// {
|
||||
// ProjectiveCurvePoint p = INFINITY;
|
||||
|
||||
// return new BooleanConditional()
|
||||
// .requires(obj != null)
|
||||
// .requires(GetType().IsInstanceOfType(obj))
|
||||
// .does( () => { p = (ProjectiveCurvePoint)obj; } )
|
||||
// .requires(this.Curve == p.Curve)
|
||||
// .requires(this.X == p.X)
|
||||
// .requires(this.Y == p.Y)
|
||||
// .requires(this.Z == p.Z)
|
||||
// .isSuccess();
|
||||
// }
|
||||
|
||||
// public ProjectiveCurvePoint doubled()
|
||||
// {
|
||||
// BigInteger s = Curve.Fp.Fit(Y * Z);
|
||||
// BigInteger B = Curve.Fp.Fit(X * Y * s);
|
||||
// BigInteger w = Curve.Fp.Fit(
|
||||
// (Curve.a * BigInteger.Pow(Z,2)) +
|
||||
// (BigInteger.Pow(X,2) * 3)
|
||||
// );
|
||||
// BigInteger h = Curve.Fp.Fit(w.Pow(2) - (B * 8));
|
||||
|
||||
// BigInteger xd = h * s * 2;
|
||||
// BigInteger yd = (
|
||||
// (w * ((B * 4) - h)) -
|
||||
// (Y.Pow(2) * s.Pow(2) * 8)
|
||||
// );
|
||||
// BigInteger zd = s.Pow(3) * 8;
|
||||
|
||||
// xd = Curve.Fp.Fit(xd);
|
||||
// yd = Curve.Fp.Fit(yd);
|
||||
// zd = Curve.Fp.Fit(zd);
|
||||
|
||||
// return new ProjectiveCurvePoint(Curve,xd,yd,zd);
|
||||
// }
|
||||
|
||||
// public ProjectiveCurvePoint add(ProjectiveCurvePoint p){
|
||||
// BigInteger u = Curve.Fp.Fit( (p.Y * Z) - (Y * p.Z) );
|
||||
// BigInteger v = Curve.Fp.Fit( (p.X * Z) - (X * p.Z) );
|
||||
// BigInteger A = Curve.Fp.Fit(
|
||||
// (Z * p.Z * u.Pow(2)) - v.Pow(3) - (v.Pow(2) * X * p.Z * 2)
|
||||
// );
|
||||
|
||||
// BigInteger xd = v * A;
|
||||
// BigInteger yd = (
|
||||
// (u * ((X * p.Z * v.Pow(2)) - A)) -
|
||||
// (v.Pow(3) * Y * p.Z)
|
||||
// );
|
||||
// BigInteger zd = Z * p.Z * v.Pow(3);
|
||||
|
||||
// xd = Curve.Fp.Fit(xd);
|
||||
// yd = Curve.Fp.Fit(yd);
|
||||
// zd = Curve.Fp.Fit(zd);
|
||||
|
||||
// if (zd == 0){
|
||||
// return INFINITY;
|
||||
// }
|
||||
|
||||
// return new ProjectiveCurvePoint(Curve, xd, yd, zd);
|
||||
// }
|
||||
|
||||
// public ProjectiveCurvePoint Negated(){
|
||||
// return new ProjectiveCurvePoint(Curve, X, Curve.Fp.AdditiveInverse(Y), Z);
|
||||
// }
|
||||
|
||||
|
||||
// public override string ToString()
|
||||
// {
|
||||
// return string.Format("[ProjectiveCurvePoint: Curve=... X={1} Y={2} Z={3}]", Curve,X,Y,Z);
|
||||
// }
|
||||
|
||||
// public static implicit operator ProjectiveCurvePoint(CurvePoint p){
|
||||
// return new ProjectiveCurvePoint(p);
|
||||
// }
|
||||
|
||||
// public static ProjectiveCurvePoint operator +(ProjectiveCurvePoint p1, ProjectiveCurvePoint p2)
|
||||
// {
|
||||
// if ((object)p1 == INFINITY){
|
||||
// return p2;
|
||||
// } else if ((object)p2 == INFINITY){
|
||||
// return p1;
|
||||
// } else if (p1.Equals(p2)){
|
||||
// return p1.doubled();
|
||||
// } else {
|
||||
// return p1.add(p2);
|
||||
// }
|
||||
// }
|
||||
// public static ProjectiveCurvePoint operator -(ProjectiveCurvePoint p1, ProjectiveCurvePoint p2)
|
||||
// {
|
||||
// if ((object)p1 == INFINITY)
|
||||
// {
|
||||
// return p2;
|
||||
// }
|
||||
// else if ((object)p2 == INFINITY)
|
||||
// {
|
||||
// return p1;
|
||||
// }
|
||||
// return p1 + p2.Negated();
|
||||
// }
|
||||
// public static ProjectiveCurvePoint operator *(ProjectiveCurvePoint p1, Integer n)
|
||||
// {
|
||||
// if ((object)p1 == (object)INFINITY)
|
||||
// {
|
||||
// return INFINITY;
|
||||
// }
|
||||
|
||||
// if (p1.Y == BigInteger.Zero)
|
||||
// {
|
||||
// return INFINITY;
|
||||
// }
|
||||
|
||||
// if (n.isZero())
|
||||
// {
|
||||
// throw new NotImplementedException("CurevPoint * 0");
|
||||
// }
|
||||
|
||||
// ProjectiveCurvePoint result = null;
|
||||
// ProjectiveCurvePoint p = p1;
|
||||
|
||||
// int i;
|
||||
// int bitwidth = n.Log2();
|
||||
|
||||
// if (bitwidth < 0)
|
||||
// {
|
||||
// bitwidth = -bitwidth;
|
||||
// }
|
||||
|
||||
// for (i = 0; i < bitwidth; i++)
|
||||
// {
|
||||
// if (n[i])
|
||||
// break;
|
||||
|
||||
// p += p;
|
||||
// }
|
||||
|
||||
// result = p;
|
||||
|
||||
// for (i++; i <= bitwidth; i++)
|
||||
// {
|
||||
// p += p;
|
||||
// if (n[i])
|
||||
// {
|
||||
// result = p + result;
|
||||
// }
|
||||
// }
|
||||
|
||||
// return result;
|
||||
// }
|
||||
|
||||
// }
|
||||
// }
|
|
@ -0,0 +1,9 @@
|
|||
using System.Security.Cryptography;
|
||||
|
||||
namespace ln.crypto.ec
|
||||
{
|
||||
public static class SHA256Extensions
|
||||
{
|
||||
public static void TransformBlock(this SHA256 sha256, byte[] input) => sha256.TransformBlock(input,0,input.Length, null, 0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
<ProjectReference Include="../../ln.biginteger/ln.biginteger/ln.biginteger.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,133 @@
|
|||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using Crypto.EC;
|
||||
using System.Numerics;
|
||||
|
||||
namespace ln.crypto.ec.lsag
|
||||
{
|
||||
public static class LSAG
|
||||
{
|
||||
public static RandomNumberGenerator RandomNumberGenerator { get; } = RandomNumberGenerator.Create();
|
||||
|
||||
public static void Sign(byte[] message, EllipticCurve curve, BigInteger signKey, CurvePoint[] publicKeys, out Signature signature)
|
||||
{
|
||||
Sign(message, curve, signKey, publicKeys, out BigInteger c0, out BigInteger[] s, out CurvePoint Y);
|
||||
signature = new Signature(c0, s, Y);
|
||||
}
|
||||
public static void Sign(byte[] message, EllipticCurve curve, BigInteger signKey, CurvePoint[] publicKeys, out BigInteger C0, out BigInteger[] s,out CurvePoint Y)
|
||||
{
|
||||
if (message.Length > 32)
|
||||
message = SHA256.Create().ComputeHash(message);
|
||||
|
||||
BigInteger[] c = new BigInteger[publicKeys.Length];
|
||||
s = new BigInteger[publicKeys.Length];
|
||||
CurvePoint signPubKey = curve.G * signKey;
|
||||
int signPubKeyIndex = -1;
|
||||
|
||||
for (int i=0;i<publicKeys.Length; i++)
|
||||
{
|
||||
if (signPubKey.Equals(publicKeys[i]))
|
||||
signPubKeyIndex = i;
|
||||
}
|
||||
|
||||
if (signPubKeyIndex == -1)
|
||||
throw new ArgumentException("public key of signer not found");
|
||||
|
||||
byte[] publicKeysHash = HashCurvePoints(publicKeys);
|
||||
|
||||
CurvePoint H = curve.HashToPoint(publicKeysHash);
|
||||
Y = H * signKey;
|
||||
|
||||
BigInteger u = GetRandom(curve.n);
|
||||
c[(signPubKeyIndex + 1) % publicKeys.Length] = H1(curve, publicKeysHash, Y, message, curve.G * u, H * u);
|
||||
|
||||
for (int i = (signPubKeyIndex+1) % publicKeys.Length; i != signPubKeyIndex; i = (i+1) % publicKeys.Length)
|
||||
{
|
||||
s[i] = GetRandom(curve.n);
|
||||
CurvePoint z1 = (curve.G * s[i]) + (publicKeys[i] * c[i]);
|
||||
CurvePoint z2 = (H * s[i]) + (Y * c[i]);
|
||||
|
||||
c[(i+1)%publicKeys.Length] = H1(curve, publicKeysHash, Y, message, z1, z2);
|
||||
}
|
||||
|
||||
s[signPubKeyIndex] = u - (signKey * c[signPubKeyIndex]);
|
||||
s[signPubKeyIndex] = s[signPubKeyIndex] % curve.n;
|
||||
if (s[signPubKeyIndex] < 0)
|
||||
s[signPubKeyIndex] += curve.n;
|
||||
C0 = c[0];
|
||||
}
|
||||
|
||||
public static bool Verify(EllipticCurve curve, byte[] message, CurvePoint[] publicKeys, Signature signature) => Verify(curve, message, publicKeys, signature.C0, signature.s, signature.Y);
|
||||
public static bool Verify(EllipticCurve curve, byte[] message, CurvePoint[] publicKeys, BigInteger C0, BigInteger[] s, CurvePoint Y)
|
||||
{
|
||||
if (message.Length > 32)
|
||||
message = SHA256.Create().ComputeHash(message);
|
||||
|
||||
BigInteger[] c = new BigInteger[publicKeys.Length+1];
|
||||
c[0] = C0;
|
||||
|
||||
byte[] publicKeysHash = HashCurvePoints(publicKeys);
|
||||
|
||||
CurvePoint H = curve.HashToPoint(publicKeysHash);
|
||||
|
||||
for (int i=0;i<publicKeys.Length; i++)
|
||||
{
|
||||
CurvePoint z1 = (curve.G * s[i]) + (publicKeys[i] * c[i]);
|
||||
CurvePoint z2 = (H * s[i]) + (Y * c[i]);
|
||||
c[i+1] = H1(curve, publicKeysHash, Y, message, z1, z2);
|
||||
}
|
||||
|
||||
return c[0] == c[publicKeys.Length];
|
||||
}
|
||||
|
||||
public static BigInteger H1(EllipticCurve curve, CurvePoint[] publicKeys, CurvePoint Y, byte[] message, CurvePoint a, CurvePoint b) => H1(curve, HashCurvePoints(publicKeys), Y, message, a, b);
|
||||
public static BigInteger H1(EllipticCurve curve, byte[] publicKeysHash, CurvePoint Y, byte[] message, CurvePoint a, CurvePoint b)
|
||||
{
|
||||
SHA256 sha256 = SHA256.Create();
|
||||
sha256.TransformBlock(publicKeysHash);
|
||||
sha256.TransformBlock(Y.ToByteArray());
|
||||
sha256.TransformBlock(message);
|
||||
sha256.TransformBlock(a.ToByteArray());
|
||||
sha256.TransformBlock(b.ToByteArray());
|
||||
sha256.TransformFinalBlock(new byte[0],0,0);
|
||||
return curve.Fp.Fit(new BigInteger(sha256.Hash));
|
||||
}
|
||||
|
||||
public static byte[] HashCurvePoints(CurvePoint[] curvePoints)
|
||||
{
|
||||
SHA256 sha256 = SHA256.Create();
|
||||
foreach (CurvePoint cp in curvePoints)
|
||||
sha256.TransformBlock(cp.ToByteArray());
|
||||
return sha256.TransformFinalBlock(new byte[0],0,0);
|
||||
}
|
||||
|
||||
|
||||
public static BigInteger GetRandom(BigInteger maxExclusive)
|
||||
{
|
||||
byte[] bytes = new byte[maxExclusive.GetByteCount()];
|
||||
RandomNumberGenerator.GetBytes(bytes);
|
||||
BigInteger result = new BigInteger(bytes) % maxExclusive;
|
||||
if (result < 0)
|
||||
result += maxExclusive;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public class Signature
|
||||
{
|
||||
public BigInteger C0 { get; }
|
||||
public BigInteger[] s { get; }
|
||||
public CurvePoint Y { get; }
|
||||
|
||||
public Signature(BigInteger C0, BigInteger[] s, CurvePoint Y)
|
||||
{
|
||||
this.C0 = C0;
|
||||
this.s = (BigInteger[])s.Clone();
|
||||
this.Y = Y;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue