Skip to content

Instantly share code, notes, and snippets.

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

This comment has been minimized.

Copy link
Owner Author

@Coding-Enthusiast Coding-Enthusiast commented Jan 19, 2019

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