Skip to content

Instantly share code, notes, and snippets.

@Zenithar
Last active July 3, 2023 15:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Zenithar/ac72f1bc206f418e3c2b42de2dcc79e0 to your computer and use it in GitHub Desktop.
Save Zenithar/ac72f1bc206f418e3c2b42de2dcc79e0 to your computer and use it in GitHub Desktop.
Schnorr signature aggregation with MuSig in Go.
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"fmt"
"math/big"
"os"
)
func main() {
// https://eprint.iacr.org/2018/068 - Simple Schnorr Multi-Signatures with Applications to Bitcoin
//
// Inspired from https://medium.com/asecuritysite-when-bob-met-alice/multiple-signers-and-key-aggregation-with-schnorr-be0868133876
// https://asecuritysite.com/schnorr/schnorr_test3
// Use MuSig signature aggregation with P256 curve.
msg := []byte("Hello")
curve := elliptic.P256()
// X1 = x1 . G
x1, err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil {
panic(err)
}
X1 := x1.PublicKey
// R1 = r1 . G
r1, err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil {
panic(err)
}
R1 := r1.PublicKey
// X2 = x2 . G
x2, err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil {
panic(err)
}
X2 := x2.PublicKey
// R2 = r2 . G
r2, err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil {
panic(err)
}
R2 := r2.PublicKey
// X3 = x3 . G
x3, err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil {
panic(err)
}
X3 := x3.PublicKey
// R3 = r3 . G
r3, err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil {
panic(err)
}
R3 := r3.PublicKey
// L = H(X1 || X2 || X3)
h := sha256.New()
h.Write(X1.X.Bytes())
h.Write(X1.Y.Bytes())
h.Write(X2.X.Bytes())
h.Write(X2.Y.Bytes())
h.Write(X3.X.Bytes())
h.Write(X3.Y.Bytes())
L := h.Sum(nil)
// H1 = H( L || X1 ) . X1
h.Reset()
h.Write(L)
h.Write(X1.X.Bytes())
h.Write(X1.Y.Bytes())
Xx1, Xy1 := curve.ScalarMult(X1.X, X1.Y, h.Sum(nil))
// H2 = H( L || X2 ) . X2
h.Reset()
h.Write(L)
h.Write(X2.X.Bytes())
h.Write(X2.Y.Bytes())
Xx2, Xy2 := curve.ScalarMult(X2.X, X2.Y, h.Sum(nil))
// H3 = H( L || X3 ) . X3
h.Reset()
h.Write(L)
h.Write(X3.X.Bytes())
h.Write(X3.Y.Bytes())
Xx3, Xy3 := curve.ScalarMult(X3.X, X3.Y, h.Sum(nil))
// X = X1 + X2 + X3
Xx, Xy := curve.Add(Xx1, Xy1, Xx2, Xy2)
Xx, Xy = curve.Add(Xx, Xy, Xx3, Xy3)
X := append(Xx.Bytes(), Xy.Bytes()...)
// R = R1 + R2 + R3
Rx, Ry := curve.Add(R1.X, R1.Y, R2.X, R2.Y)
Rx, Ry = curve.Add(Rx, Ry, R3.X, R3.Y)
R := append(Rx.Bytes(), Ry.Bytes()...)
// H(X, R, m)
h.Reset()
h.Write(X)
h.Write(R)
h.Write(msg)
HXRm := big.NewInt(0).SetBytes(h.Sum(nil))
// HLX1 = H(L, X1)
h.Reset()
h.Write(L)
h.Write(X1.X.Bytes())
h.Write(X1.Y.Bytes())
HLX1 := big.NewInt(0).SetBytes(h.Sum(nil))
// HLX2 = H(L, X2)
h.Reset()
h.Write(L)
h.Write(X2.X.Bytes())
h.Write(X2.Y.Bytes())
HLX2 := big.NewInt(0).SetBytes(h.Sum(nil))
// HLX3 = H(L, X3)
h.Reset()
h.Write(L)
h.Write(X3.X.Bytes())
h.Write(X3.Y.Bytes())
HLX3 := big.NewInt(0).SetBytes(h.Sum(nil))
// Compute signatures
s1 := new(big.Int).Add(r1.D, new(big.Int).Mul(new(big.Int).Mul(HXRm, HLX1), x1.D))
s2 := new(big.Int).Add(r2.D, new(big.Int).Mul(new(big.Int).Mul(HXRm, HLX2), x2.D))
s3 := new(big.Int).Add(r3.D, new(big.Int).Mul(new(big.Int).Mul(HXRm, HLX3), x3.D))
s := new(big.Int).Add(s1, s2)
s = s.Add(s, s3)
fmt.Fprintf(os.Stdout, "Bob Private key (x1) = %s\n", x1.D.Text(16))
fmt.Fprintf(os.Stdout, "Bob Public key (X1) = (%s, %s)\n", X1.X.Text(16), X1.Y.Text(16))
fmt.Fprintf(os.Stdout, "Alice Private key (x2) = %s\n", x2.D.Text(16))
fmt.Fprintf(os.Stdout, "Alice Public key (X2) = (%s, %s)\n", X2.X.Text(16), X2.Y.Text(16))
fmt.Fprintf(os.Stdout, "Charlie Private key (x3) = %s\n", x3.D.Text(16))
fmt.Fprintf(os.Stdout, "Charlie Public key (X3) = (%s, %s)\n", X3.X.Text(16), X3.Y.Text(16))
fmt.Fprintf(os.Stdout, "\nMerged Public Key X = (%s, %s)\n", Xx.Text(16), Xy.Text(16))
fmt.Fprintf(os.Stdout, "\nBob s1 = %s\n", s1.Text(16))
fmt.Fprintf(os.Stdout, "Alice s2 = %s\n", s2.Text(16))
fmt.Fprintf(os.Stdout, "Charlie s3 = %s\n", s3.Text(16))
fmt.Fprintf(os.Stdout, "\nMerged s = %x\n", s.Bytes())
fmt.Fprintf(os.Stdout, "Merged R = %x\n", R)
// Verify signature
// sG = s . G
sGx, sGy := curve.ScalarBaseMult(s.Bytes())
// H(X,R,m)
h.Reset()
h.Write(X)
h.Write(R)
h.Write(msg)
hRXm := h.Sum(nil)
// H(X,R,m) . X
Cx, Cy := curve.ScalarMult(Xx, Xy, hRXm)
// R + H(X,R,m) . X
rX, rY := curve.Add(Rx, Ry, Cx, Cy)
// s . G == R + H(X,R,m) . X
if sGx.Cmp(rX) == 0 && sGy.Cmp(rY) == 0 {
fmt.Fprintln(os.Stdout, "\nSignature verified")
} else {
fmt.Fprintln(os.Stdout, "\nSignature verification error")
}
}
Bob Private key (x1) = 7b0405c0f430e28b36c7ad6e9b41bb5f6361d7bfe6df54e99b363dfee9e89b42
Bob Public key (X1) = (dbe75cf345f45b71103efbbbf1826c61010c21cbbb5e772bb691afc66933a0fe, 443e5bf138a74fbac23540a726135213579b7a5f2b7c1930eeed4e2430e6d7f4)
Alice Private key (x2) = de7d6db3d555ac908afac73d3c027a5bbca290fe41bcb25cc918aa0d5f62b58f
Alice Public key (X2) = (9b50304a3b3f8bd9b9b82a6a479324591d21746db417de8e258bbb829cb9bdb1, 9192c64a1612fca147d0362b9c3a6916f4bed9a48b2bf2e16beff984d7816347)
Charlie Private key (x3) = 399b8a393803036a9e9aae248e94da1389d2cd21da56174ae3a70bf1b7d80952
Charlie Public key (X3) = (47755a59346a2077541eb864bc3f73d25d4ae0170d79a36834c36401f3858048, 7cb1f202a161d6f43f883501d57028d1c27d3a9954e86b9eb73efea1b895623d)
Merged Public Key X = (e37d2d5c4ae1859f75088c90ab18f5b132de868efa848e381b8929c18f124396, 940cd556f952aebfb01ce570a6cadc2fa5204161a29840b957136e17ebaf5a74)
Bob s1 = 5d31d8e8b2eb72935fef040a9e1fd8f2cc62f58abf13c7026dcbf9090948de9a879126d9dca3c28499a705e4112fc17c1752b802092a7c8d906da28b09fedb20f81376f335606ba1c84055c5c9cf254fc901ef38bcee364a4995be5e79b2d92
Alice s2 = 889cfd39cb02cee45171032efee3708a39292ac7f97ddf1c9e330116facbc9f82a5ac1c17af2703a99021adce2835adb823425ffddb0824e90c5b970955aa605aedcaa9288bf0b309ec27afec691c0b9b334c8468213bc90038ce9e343c5407
Charlie s3 = 237608e17e3a22b4537e44aeeac5c90f497f336c4155ec5c2198cad8d9cd441513671ea4a2a26f55b49ca0b9935ad7c4ac7e27e8a95fba96b9617ec98061c037ed14887af8987e7d4740d50fc5fcd2cf0f428bb14df8e8b5dd2db7e966a746c
Merged s = 10944df03fc28642c04de4be887c9128c4f0b53bef9e7927b2d97c4f8dde1eca7c553073ffa38a214e745c17a870df41c460505ea903ab972da94dac51fbb415e9404aa00b6b7f54fae43a5d4565db8d88b7943308cfadb902a50602b241f605
Merged R = 9ff09a9cf32fbf54b32ccc23d6bcb3cea3d970c67217875e6404f338714519d1c9328b3035e75af12d631aac071534aa5047bdf36d8528ec5e9fadc8b274cf16
Signature verified
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment