Skip to content

Instantly share code, notes, and snippets.

@Coding-Enthusiast
Last active February 21, 2019 07:33
Embed
What would you like to do?
Schnorr signatures using MuSig and the simple collective signature proposed for Ed25519 before
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);
}
}
}
@Coding-Enthusiast
Copy link
Author

Output:

MuSig:
False

Simple addition method:
True

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment