Skip to content

Instantly share code, notes, and snippets.

@cpacia
Created March 3, 2020 22:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save cpacia/3dc7d543638f25467a14da59ba74a16a to your computer and use it in GitHub Desktop.
Save cpacia/3dc7d543638f25467a14da59ba74a16a to your computer and use it in GitHub Desktop.
Go MuSig Example
package main
import (
"crypto/rand"
"fmt"
"github.com/gcash/bchd/bchec"
"log"
)
func main() {
// This is the message we want to sign
message := []byte("Hello World")
// Both Alice and Bob will independently generate their keypairs that they are going to
// use for this joint address.
alicePrivKey, err := bchec.NewPrivateKey(bchec.S256())
if err != nil {
log.Fatal(err)
}
bobPrivKey, err := bchec.NewPrivateKey(bchec.S256())
if err != nil {
log.Fatal(err)
}
// Alice and Bob share their public keys and aggregate them together into a single public key.
aggregatePubkey, err := bchec.AggregatePublicKeys(alicePrivKey.PubKey(), bobPrivKey.PubKey())
if err != nil {
log.Fatal(err)
}
// Both Alice and Bob will create a new session object which will be used to manage signing. Before
// doing so they need to generated a random session ID.
var (
aliceSessionID [32]byte
bobSessionID [32]byte
)
rand.Read(aliceSessionID[:])
rand.Read(bobSessionID[:])
aliceSession, err := bchec.NewMuSession([]*bchec.PublicKey{alicePrivKey.PubKey(), bobPrivKey.PubKey()}, alicePrivKey, aliceSessionID)
if err != nil {
log.Fatal(err)
}
bobSession, err := bchec.NewMuSession([]*bchec.PublicKey{alicePrivKey.PubKey(), bobPrivKey.PubKey()}, bobPrivKey, bobSessionID)
if err != nil {
log.Fatal(err)
}
// Next both Alice and Bob will generate commitments and exchange them.
aliceCommitment := aliceSession.NonceCommitment(message)
bobCommitment := bobSession.NonceCommitment(message)
// After exchanging commitments both Alice and Bob import them into their session.
aliceSession.SetNonceCommitments(aliceCommitment, bobCommitment)
bobSession.SetNonceCommitments(aliceCommitment, bobCommitment)
// Now they can both exchange nonces
aliceNonce, err := aliceSession.Nonce()
if err != nil {
log.Fatal(err)
}
bobNonce, err := bobSession.Nonce()
if err != nil {
log.Fatal(err)
}
// After exchanging them both Alice and Bob import them into their session.
aliceSession.SetNonces(aliceNonce, bobNonce)
bobSession.SetNonces(aliceNonce, bobNonce)
// Now Alice and Bob can generate their signatures. Technically both will use the nonce public
// keys to calculate the signature's R value so they only actually share the S value.
aliceSig, err := aliceSession.Sign(message)
if err != nil {
log.Fatal(err)
}
bobSig, err := bobSession.Sign(message)
if err != nil {
log.Fatal(err)
}
// Alice and Bob share their S value with each other and then they can make an aggregate signature.
aggregateSig := aliceSession.AggregateSignature(aliceSig, bobSig)
// Now we can just verify and make sure everything worked
valid := aggregateSig.Verify(message, aggregatePubkey)
fmt.Println(valid) // True
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment