Skip to content

Instantly share code, notes, and snippets.

@msinkec
Last active March 3, 2024 07:11
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 msinkec/27f8235dd3ad94b64829def5408acec5 to your computer and use it in GitHub Desktop.
Save msinkec/27f8235dd3ad94b64829def5408acec5 to your computer and use it in GitHub Desktop.
TSS Example
Deployed contract: 3c0d8b44f8740a0c45162fa6bb6835808b9b04a884853fcb597af1a0812d6345
tx: 010000000145632d81a0f17a59cb3f8584a8049b8b803568bba62f16450c0a74f8448b0d3c0000000000ffffffff0184030000000000001976a91446f320a7e7325a41829e13b016f1dfceee8ab37388ac00000000
sighash preimage: 01000000d544095762018685b1125f75040495deae1a6a78063ca09313aa0f827c6618a43bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e7066504445632d81a0f17a59cb3f8584a8049b8b803568bba62f16450c0a74f8448b0d3c000000001976a914f2a684c7ada5dd4c447ce03f2e50990c0e181f0488ace803000000000000ffffffff4657a850644e1a190c4b06bf681443752eddb949cce4c81751db4c45c61052990000000041000000
sighash f7ab4253b131f70e698051aa621d1ae09665500ef4580d0d2decbc0d4b863671
Sig (r, s): 114836438995585026443311608703469012746226023187493091108812467319065332271518 46571976558762956347626225494771745362039354849912631975526154502213652815393
Sig (hex): 3045022100fde31f027463d4390a9a575f9f5939d602da393c55e8f5b0a31d246d6595c99e022066f6cdfb03abc3b27ab4f88c501f9388ed25602dab53f9d67aadf18343a19e2141
tx (signed): 010000000145632d81a0f17a59cb3f8584a8049b8b803568bba62f16450c0a74f8448b0d3c000000006b483045022100fde31f027463d4390a9a575f9f5939d602da393c55e8f5b0a31d246d6595c99e022066f6cdfb03abc3b27ab4f88c501f9388ed25602dab53f9d67aadf18343a19e21412102a89d4d9bf1e8c8689ff79e3aaa35375c5686829238b31cc605bd2b903a4bae85ffffffff0184030000000000001976a91446f320a7e7325a41829e13b016f1dfceee8ab37388ac00000000
Call: cfc1704361367d902da142c3307c4d0ef9cfe6c6e5d882af258c3a1964ebe9b5
Links:
https://test.whatsonchain.com/tx/3c0d8b44f8740a0c45162fa6bb6835808b9b04a884853fcb597af1a0812d6345
https://test.whatsonchain.com/tx/cfc1704361367d902da142c3307c4d0ef9cfe6c6e5d882af258c3a1964ebe9b5
package main
import (
"crypto/ecdsa"
"crypto/sha256"
"encoding/hex"
"fmt"
"math/big"
"runtime"
"sync/atomic"
"testing"
"golang.org/x/crypto/ripemd160"
"github.com/ipfs/go-log"
"github.com/stretchr/testify/assert"
"github.com/bnb-chain/tss-lib/v2/common"
"github.com/bnb-chain/tss-lib/v2/ecdsa/keygen"
"github.com/bnb-chain/tss-lib/v2/test"
"github.com/bnb-chain/tss-lib/v2/tss"
)
const (
testParticipants = 5
testThreshold = 3
)
func setUp(level string) {
if err := log.SetLogLevel("tss-lib", level); err != nil {
panic(err)
}
}
func main() {
setUp("info")
threshold := testThreshold
// PHASE: load keygen fixtures
keys, signPIDs, err := keygen.LoadKeygenTestFixturesRandomSet(testThreshold+1, testParticipants)
pubKeyHex := publicKeyToHexCompressed(keys[0].ECDSAPub.ToECDSAPubKey())
addrHex, _ := compressedPubKeyToAddress(pubKeyHex)
fmt.Printf("Pub Key (x, y): %s %s\n", keys[0].ECDSAPub.X(), keys[0].ECDSAPub.Y())
fmt.Printf("Pub Key (hex, compressed): %s\n", pubKeyHex)
fmt.Printf("Address (hex): %s\n", addrHex)
// PHASE: signing
// use a shuffled selection of the list of parties for this test
p2pCtx := tss.NewPeerContext(signPIDs)
parties := make([]*LocalParty, 0, len(signPIDs))
errCh := make(chan *tss.Error, len(signPIDs))
outCh := make(chan tss.Message, len(signPIDs))
endCh := make(chan *common.SignatureData, len(signPIDs))
updater := test.SharedPartyUpdater
msgData, _ := hex.DecodeString("f7ab4253b131f70e698051aa621d1ae09665500ef4580d0d2decbc0d4b863671") // TODO: Put tx sighash here
// init the parties
for i := 0; i < len(signPIDs); i++ {
params := tss.NewParameters(tss.S256(), p2pCtx, signPIDs[i], len(signPIDs), threshold)
P := NewLocalParty(new(big.Int).SetBytes(msgData), params, keys[i], outCh, endCh, len(msgData)).(*LocalParty)
parties = append(parties, P)
go func(P *LocalParty) {
if err := P.Start(); err != nil {
errCh <- err
}
}(P)
}
var ended int32
signing:
for {
fmt.Printf("ACTIVE GOROUTINES: %d\n", runtime.NumGoroutine())
select {
case err := <-errCh:
common.Logger.Errorf("Error: %s", err)
break signing
case msg := <-outCh:
dest := msg.GetTo()
if dest == nil {
for _, P := range parties {
if P.PartyID().Index == msg.GetFrom().Index {
continue
}
go updater(P, msg, errCh)
}
} else {
if dest[0].Index == msg.GetFrom().Index {
fmt.Printf("party %d tried to send a message to itself (%d)", dest[0].Index, msg.GetFrom().Index)
exit(1)
}
go updater(parties[dest[0].Index], msg, errCh)
}
case <-endCh:
atomic.AddInt32(&ended, 1)
if atomic.LoadInt32(&ended) == int32(len(signPIDs)) {
fmt.Printf("Done. Received signature data from %d participants", ended)
R := parties[0].temp.bigR
//r := parties[0].temp.rx
modN := common.ModInt(tss.S256().Params().N)
// BEGIN check s correctness
sumS := big.NewInt(0)
for _, p := range parties {
sumS = modN.Add(sumS, p.temp.si)
}
// END check s correctness
fmt.Printf("Sig (r, s): %s %s\n", R.X(), sumS)
// BEGIN ECDSA verify
pkX, pkY := keys[0].ECDSAPub.X(), keys[0].ECDSAPub.Y()
pk := ecdsa.PublicKey{
Curve: tss.EC(),
X: pkX,
Y: pkY,
}
ok := ecdsa.Verify(&pk, msgData, R.X(), sumS)
fmt.Println(ok)
// END ECDSA verify
break signing
}
}
}
}
func fillBytes(x *big.Int, buf []byte) []byte {
b := x.Bytes()
if len(b) > len(buf) {
panic("buffer too small")
}
offset := len(buf) - len(b)
for i := range buf {
if i < offset {
buf[i] = 0
} else {
buf[i] = b[i-offset]
}
}
return buf
}
// Serializes a public key into compressed form (0x02/0x03 + x)
func publicKeyToHexCompressed(pubKey *ecdsa.PublicKey) string {
xBytes := pubKey.X.Bytes()
// Ensure the bytes are 32 bytes long
paddedX := append(make([]byte, 32-len(xBytes)), xBytes...)
var compressed []byte
if pubKey.Y.Bit(0) == 0 { // Even Y
compressed = append([]byte{0x02}, paddedX...)
} else { // Odd Y
compressed = append([]byte{0x03}, paddedX...)
}
return hex.EncodeToString(compressed)
}
// Converts a hex-encoded compressed public key to a Bitcoin address
func compressedPubKeyToAddress(compressedPubKeyHex string) (string, error) {
// Decode the hex-encoded compressed public key
pubKeyBytes, err := hex.DecodeString(compressedPubKeyHex)
if err != nil {
return "", err
}
// SHA-256 hashing
shaHash := sha256.New()
shaHash.Write(pubKeyBytes)
shaResult := shaHash.Sum(nil)
// RIPEMD-160 hashing
r160Hash := ripemd160.New()
r160Hash.Write(shaResult)
ripemdResult := r160Hash.Sum(nil)
return hex.EncodeToString(ripemdResult), nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment