Last active
February 21, 2019 07:33
-
-
Save Coding-Enthusiast/6596a29fe361695a169f40ffd7d1e1f7 to your computer and use it in GitHub Desktop.
Schnorr signatures using MuSig and the simple collective signature proposed for Ed25519 before
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Autarkysoft.Cryptocurrency; // Library not public yet! | |
using Autarkysoft.Cryptocurrency.Coins; | |
using Autarkysoft.Cryptocurrency.Cryptography.Asymmetric.EllipticCurve; | |
using Autarkysoft.Cryptocurrency.Cryptography.Hashing; | |
using Autarkysoft.Cryptocurrency.Extensions; | |
using Autarkysoft.Cryptocurrency.KeyPairs; | |
using System; | |
using System.Numerics; | |
namespace TestLibrary | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
Console.WriteLine("MuSig:"); | |
MuSig(); | |
Console.WriteLine(); | |
Console.WriteLine("Simple addition method:"); | |
Alternate(); | |
Console.ReadLine(); | |
} | |
private static void MuSig() | |
{ | |
ICoin btc = new Bitcoin(); | |
EllipticCurveCalculator calc = new EllipticCurveCalculator(btc); | |
IRandomNumberGenerator rng = new SharpRandom(); // implementation of a strong RNG | |
byte[] msg = new byte[32]; | |
rng.GetBytes(msg);// random 256 bit message | |
PrivateKey x1 = new PrivateKey(btc);// random key | |
PublicKey X1 = x1.ToPublicKey(); | |
PrivateKey x2 = new PrivateKey(btc); | |
PublicKey X2 = x2.ToPublicKey(); | |
//EllipticCurvePoint L = calc.Add(X1.ToPoint(), X2.ToPoint());// calc.Add() does point addition | |
//BigInteger a1 = H(PointToBytes(calc.Add(L, X1.ToPoint()))); | |
//BigInteger a2 = H(PointToBytes(calc.Add(L, X2.ToPoint()))); | |
BigInteger a1 = H(X1.ToBytes(true), X2.ToBytes(true), X1.ToBytes(true));// try with concatinating pubkey bytes (shouldn't make a difference | |
BigInteger a2 = H(X1.ToBytes(true), X2.ToBytes(true), X2.ToBytes(true)); | |
EllipticCurvePoint X0 = calc.Add( | |
calc.Multiply(a1, X1.ToPoint()), | |
calc.Multiply(a2, X2.ToPoint()));// X0 is X with ~ on top of it! or aggregated public key | |
byte[] rnd1 = new byte[32]; | |
rng.GetBytes(rnd1);// skip < N check for bravity | |
BigInteger r1 = rnd1.ToBigInt(true, true);// treats bytes as big endian and removes starting zero if it existed | |
EllipticCurvePoint R1 = calc.Multiply(r1, btc.Curve.G); | |
var t1 = H(PointToBytes(R1)); // t's are useless here! | |
byte[] rnd2 = new byte[32]; | |
rng.GetBytes(rnd2); | |
BigInteger r2 = rnd2.ToBigInt(true, true); | |
EllipticCurvePoint R2 = calc.Multiply(r2, btc.Curve.G); | |
var t2 = H(PointToBytes(R2)); | |
EllipticCurvePoint R = calc.Add(R1, R2); | |
BigInteger c = H(PointToBytes(X0), PointToBytes(R), msg); | |
BigInteger s1 = (r1 + (c * a1 * x1.ToBigInt())) % btc.Curve.P; | |
BigInteger s2 = (r2 + (c * a2 * x2.ToBigInt())) % btc.Curve.P; | |
BigInteger s = (s1 + s2) % btc.Curve.P; | |
// verification | |
EllipticCurvePoint left = calc.Multiply(s, btc.Curve.G); | |
EllipticCurvePoint right = calc.Add(R, calc.Multiply(c, X0)); | |
Console.WriteLine(left == right); // equality checkes (P1.X == P2.X && P1.Y == P2.Y) | |
} | |
private static void Alternate() | |
{ | |
ICoin btc = new Bitcoin(); | |
EllipticCurveCalculator calc = new EllipticCurveCalculator(btc); | |
IRandomNumberGenerator rng = new SharpRandom(); | |
byte[] msg = new byte[32]; | |
rng.GetBytes(msg); | |
PrivateKey a = new PrivateKey(btc); | |
PublicKey A = a.ToPublicKey(); | |
PrivateKey b = new PrivateKey(btc); | |
PublicKey B = b.ToPublicKey(); | |
EllipticCurvePoint AplusB = calc.Add(A.ToPoint(), B.ToPoint()); | |
byte[] ha = new byte[32]; | |
byte[] hb = new byte[32]; | |
rng.GetBytes(ha); | |
rng.GetBytes(hb); | |
var ra = H(ha, msg); | |
var rb = H(hb, msg); | |
EllipticCurvePoint Ra = calc.Multiply(ra, btc.Curve.G); | |
EllipticCurvePoint Rb = calc.Multiply(rb, btc.Curve.G); | |
EllipticCurvePoint R = calc.Add(Ra, Rb); | |
BigInteger sa = ra + | |
(H(PointToBytes(R), PointToBytes(calc.Add(A.ToPoint(), B.ToPoint())), msg) | |
* a.ToBigInt()); | |
BigInteger sb = rb + | |
(H(PointToBytes(R), PointToBytes(calc.Add(A.ToPoint(), B.ToPoint())), msg) | |
* b.ToBigInt()); | |
BigInteger s = sa + sb; | |
// verification | |
EllipticCurvePoint left = calc.Multiply(s, btc.Curve.G); | |
EllipticCurvePoint right = | |
calc.Add( | |
R, | |
calc.Multiply( | |
H(PointToBytes(R), PointToBytes(AplusB), msg), | |
AplusB) | |
); | |
Console.WriteLine(left == right); | |
} | |
private static BigInteger H(params byte[][] bytes) | |
{ | |
byte[] toHash = { }; | |
foreach (byte[] item in bytes) | |
{ | |
toHash = toHash.ConcatFast(item); | |
} | |
return HashFunctions.ComputeSha256(toHash).ToBigInt(true, true); | |
} | |
private static byte[] PointToBytes(EllipticCurvePoint pt) | |
{ | |
byte firstByte = pt.Y.IsEven ? (byte)2 : (byte)3; | |
// ToByteArrayExt() returns bigendian bytes and removes initial zero indicating positive sign | |
// skip 32 byte enforcement check here since chance of it is low and doesn't make a difference. | |
return pt.X.ToByteArrayExt(true, true).AppendToBeginning(firstByte); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Output: