mirror of
https://github.com/SwingbyProtocol/tss-lib.git
synced 2026-01-08 21:37:55 -05:00
add local benchmark tools (make benchgen, make benchsign)
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,6 @@
|
||||
build
|
||||
vendor
|
||||
benchdata
|
||||
.DS_Store
|
||||
|
||||
# Binaries for programs and plugins
|
||||
|
||||
28
Makefile
28
Makefile
@@ -1,5 +1,9 @@
|
||||
MODULE = github.com/binance-chain/tss-lib
|
||||
PACKAGES = $(shell go list ./... | grep -v '/vendor/')
|
||||
ENTRYPOINT = ./cmd/...
|
||||
LD_FLAGS = -s -w
|
||||
BUILD_FLAGS = -trimpath -ldflags "$(LD_FLAGS)"
|
||||
BUILD_OUT = ./build/
|
||||
|
||||
all: protob test
|
||||
|
||||
@@ -13,9 +17,6 @@ protob:
|
||||
protoc --go_out=module=$(MODULE):. ./protob/$$file.proto ; \
|
||||
done
|
||||
|
||||
build: protob
|
||||
go fmt ./...
|
||||
|
||||
########################################
|
||||
### Format
|
||||
|
||||
@@ -25,6 +26,24 @@ fmt:
|
||||
lint:
|
||||
@golangci-lint run
|
||||
|
||||
########################################
|
||||
### Build
|
||||
|
||||
build: fmt
|
||||
@echo "--> Building bench tools"
|
||||
mkdir -p ./build
|
||||
go build ${BUILD_FLAGS} -o ${BUILD_OUT} ${ENTRYPOINT}
|
||||
@echo "\n--> Build complete"
|
||||
|
||||
########################################
|
||||
### Benchmarking
|
||||
|
||||
benchgen: fmt
|
||||
go run ./cmd/tss-benchgen benchdata
|
||||
|
||||
benchsign: fmt
|
||||
go run ./cmd/tss-benchsign benchdata
|
||||
|
||||
########################################
|
||||
### Testing
|
||||
|
||||
@@ -51,5 +70,4 @@ pre_commit: build test
|
||||
# To avoid unintended conflicts with file names, always add to .PHONY
|
||||
# # unless there is a reason not to.
|
||||
# # https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
|
||||
.PHONY: protob build test_unit test_unit_race test
|
||||
|
||||
.PHONY: protob build test_unit test_unit_race test benchgen benchsign
|
||||
|
||||
240
cmd/tss-benchgen/main.go
Normal file
240
cmd/tss-benchgen/main.go
Normal file
File diff suppressed because one or more lines are too long
266
cmd/tss-benchsign/main.go
Normal file
266
cmd/tss-benchsign/main.go
Normal file
@@ -0,0 +1,266 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/binance-chain/tss-lib/common"
|
||||
"github.com/binance-chain/tss-lib/ecdsa/keygen"
|
||||
"github.com/binance-chain/tss-lib/ecdsa/signing"
|
||||
"github.com/binance-chain/tss-lib/test"
|
||||
"github.com/binance-chain/tss-lib/tss"
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/ipfs/go-log"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/text/language"
|
||||
"golang.org/x/text/message"
|
||||
)
|
||||
|
||||
const libLogLevel = "warn"
|
||||
|
||||
type result struct {
|
||||
quorum int
|
||||
duration time.Duration
|
||||
}
|
||||
|
||||
func usage() {
|
||||
if _, err := fmt.Fprintf(os.Stderr, "usage: tss-benchsign [-flag=value, ...] datadir\n"); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
flag.PrintDefaults()
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
func main() {
|
||||
prt := message.NewPrinter(language.English)
|
||||
var (
|
||||
startQuorum = flag.Int("q", 3, "the minimum quorum (t+1) to use (default: 6)")
|
||||
endQuorum = flag.Int("n", 8, "the maximum quorum (t+1) to benchmark up to (min: 2, default: 10)")
|
||||
runs = flag.Int("r", 3, "the number of benchmarking runs (default: 3)")
|
||||
procs = flag.Int("procs", runtime.NumCPU(), "the number of max go procs (threads) to use")
|
||||
)
|
||||
flag.Usage = usage
|
||||
if flag.Parse(); !flag.Parsed() {
|
||||
usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
if *endQuorum <= 1 || *runs < 1 || *endQuorum < *startQuorum {
|
||||
fmt.Println("Error: q must be greater than 1, r must be greater than 0, endQuorum must be after startQuorum.")
|
||||
os.Exit(1)
|
||||
}
|
||||
if flag.NArg() < 1 {
|
||||
usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
dir := flag.Args()[0]
|
||||
if stat, err := os.Stat(dir); os.IsNotExist(err) || stat == nil || !stat.IsDir() {
|
||||
fmt.Printf("Error: `%s` does not exist; run tss-benchgen to generate shares first.\n", dir)
|
||||
os.Exit(1)
|
||||
}
|
||||
if _, err := os.Stat(makeKeyGenDataFilePath(dir, *endQuorum-1)); os.IsNotExist(err) {
|
||||
fmt.Printf("Error: insufficient shares for the specified quorum; run tss-benchgen and generate at least %d shares.\n", *endQuorum)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println("ECDSA/GG20 Benchmark Tool - Signing")
|
||||
fmt.Println("-----------------------------------")
|
||||
fmt.Printf("Will test quorums %d-%d in %d runs\n", *startQuorum, *endQuorum, *runs)
|
||||
fmt.Printf("Max go procs (threads): %d\n", *procs)
|
||||
fmt.Println("No network latency.")
|
||||
fmt.Println("-----------------------------------")
|
||||
|
||||
runtime.GOMAXPROCS(*procs)
|
||||
results := make([][]result, 0, *runs)
|
||||
for run := 0; run < *runs; run++ {
|
||||
fmt.Printf("Signing run %d... \n", run+1)
|
||||
results = append(results, make([]result, 0, *endQuorum))
|
||||
for q := *startQuorum; q <= *endQuorum; q++ {
|
||||
fmt.Printf(" Quorum %d... ", q)
|
||||
start := time.Now()
|
||||
runSign(dir, q-1)
|
||||
elapsed := time.Since(start)
|
||||
results[run] = append(results[run], result{
|
||||
quorum: q,
|
||||
duration: elapsed,
|
||||
})
|
||||
_, _ = prt.Printf("%d ms.\n", elapsed.Milliseconds())
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("Results summary:")
|
||||
printSummary(results)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func setUp(level string) {
|
||||
if err := log.SetLogLevel("tss-lib", level); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func runSign(dir string, t int) {
|
||||
setUp(libLogLevel)
|
||||
|
||||
q := t + 1
|
||||
keys, signPIDs, err := loadKeyGenData(dir, q)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if len(keys) != q || len(signPIDs) != q {
|
||||
panic(fmt.Errorf("wanted %d keys but got %d keys and %d signPIDs", q, len(keys), len(signPIDs)))
|
||||
}
|
||||
|
||||
msg := common.GetRandomPrimeInt(256)
|
||||
p2pCtx := tss.NewPeerContext(signPIDs)
|
||||
parties := make([]*signing.LocalParty, 0, len(signPIDs))
|
||||
|
||||
errCh := make(chan *tss.Error, len(signPIDs))
|
||||
outCh := make(chan tss.Message, len(signPIDs))
|
||||
endCh := make(chan *signing.SignatureData, len(signPIDs))
|
||||
|
||||
updater := test.SharedPartyUpdater
|
||||
|
||||
// init the parties
|
||||
for i := 0; i < len(signPIDs); i++ {
|
||||
params := tss.NewParameters(p2pCtx, signPIDs[i], len(signPIDs), t)
|
||||
P := signing.NewLocalParty(msg, params, keys[i], outCh, endCh).(*signing.LocalParty)
|
||||
parties = append(parties, P)
|
||||
go func(P *signing.LocalParty) {
|
||||
if err := P.Start(); err != nil {
|
||||
errCh <- err
|
||||
}
|
||||
}(P)
|
||||
}
|
||||
|
||||
var ended int32
|
||||
outer:
|
||||
for {
|
||||
select {
|
||||
case err := <-errCh:
|
||||
common.Logger.Errorf("Error: %s", err)
|
||||
panic(err)
|
||||
|
||||
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 {
|
||||
panic(fmt.Errorf("party %d tried to send a message to itself (%d)", dest[0].Index, msg.GetFrom().Index))
|
||||
}
|
||||
go updater(parties[dest[0].Index], msg, errCh)
|
||||
}
|
||||
|
||||
case data := <-endCh:
|
||||
atomic.AddInt32(&ended, 1)
|
||||
if atomic.LoadInt32(&ended) == int32(len(signPIDs)) {
|
||||
// BEGIN ECDSA verify
|
||||
pkX, pkY := keys[0].ECDSAPub.X(), keys[0].ECDSAPub.Y()
|
||||
pk := ecdsa.PublicKey{
|
||||
Curve: tss.EC(),
|
||||
X: pkX,
|
||||
Y: pkY,
|
||||
}
|
||||
r := new(big.Int).SetBytes(data.Signature.GetR())
|
||||
s := new(big.Int).SetBytes(data.Signature.GetS())
|
||||
var ok bool
|
||||
if ok = ecdsa.Verify(
|
||||
&pk,
|
||||
msg.Bytes(),
|
||||
r, s,
|
||||
); !ok {
|
||||
panic("ECDSA signature verification did not pass")
|
||||
}
|
||||
btcecSig := &btcec.Signature{R: r, S: s}
|
||||
if ok = btcecSig.Verify(msg.Bytes(), (*btcec.PublicKey)(&pk)); !ok {
|
||||
panic("ECDSA signature verification 2 did not pass")
|
||||
}
|
||||
break outer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func printSummary(results [][]result) {
|
||||
prt := message.NewPrinter(language.English)
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
header := []string{"Quorum"}
|
||||
for run := range results {
|
||||
header = append(header, fmt.Sprintf("Run %d", run+1))
|
||||
}
|
||||
header = append(header, "Mean")
|
||||
table.SetHeader(header)
|
||||
rows := make([][]string, 0, len(results[0]))
|
||||
for q, result := range results[0] {
|
||||
row := []string{
|
||||
prt.Sprintf("%d", result.quorum),
|
||||
}
|
||||
var avgDurationMS int64
|
||||
for run := range results {
|
||||
durationMS := results[run][q].duration.Milliseconds()
|
||||
str := prt.Sprintf("%d ms", durationMS)
|
||||
row = append(row, str)
|
||||
avgDurationMS += durationMS
|
||||
}
|
||||
avgDurationMS /= int64(len(results))
|
||||
row = append(row, prt.Sprintf("%d ms", avgDurationMS))
|
||||
rows = append(rows, row)
|
||||
}
|
||||
table.SetBorders(tablewriter.Border{Left: true, Top: true, Right: true, Bottom: true})
|
||||
table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
|
||||
table.SetAlignment(tablewriter.ALIGN_LEFT)
|
||||
table.SetCenterSeparator("|")
|
||||
table.AppendBulk(rows)
|
||||
table.Render()
|
||||
}
|
||||
|
||||
// ----- //
|
||||
|
||||
func loadKeyGenData(dir string, qty int, optionalStart ...int) ([]keygen.LocalPartySaveData, tss.SortedPartyIDs, error) {
|
||||
keys := make([]keygen.LocalPartySaveData, 0, qty)
|
||||
start := 0
|
||||
if 0 < len(optionalStart) {
|
||||
start = optionalStart[0]
|
||||
}
|
||||
for i := start; i < qty; i++ {
|
||||
fixtureFilePath := makeKeyGenDataFilePath(dir, i)
|
||||
bz, err := ioutil.ReadFile(fixtureFilePath)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err,
|
||||
"could not open the test fixture for party %d in the expected location: %s. run keygen tests first.",
|
||||
i, fixtureFilePath)
|
||||
}
|
||||
var key keygen.LocalPartySaveData
|
||||
if err = json.Unmarshal(bz, &key); err != nil {
|
||||
return nil, nil, errors.Wrapf(err,
|
||||
"could not unmarshal fixture data for party %d located at: %s",
|
||||
i, fixtureFilePath)
|
||||
}
|
||||
keys = append(keys, key)
|
||||
}
|
||||
partyIDs := make(tss.UnSortedPartyIDs, len(keys))
|
||||
for i, key := range keys {
|
||||
pMoniker := fmt.Sprintf("%d", i+start+1)
|
||||
partyIDs[i] = tss.NewPartyID(pMoniker, pMoniker, key.ShareID)
|
||||
}
|
||||
sortedPIDs := tss.SortPartyIDs(partyIDs)
|
||||
return keys, sortedPIDs, nil
|
||||
}
|
||||
|
||||
func makeKeyGenDataFilePath(dir string, partyIndex int) string {
|
||||
return fmt.Sprintf("%s/keygen_data_%d.json", dir, partyIndex)
|
||||
}
|
||||
3
go.mod
3
go.mod
@@ -12,6 +12,7 @@ require (
|
||||
github.com/ipfs/go-log/v2 v2.1.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.4
|
||||
github.com/otiai10/mint v1.3.1 // indirect
|
||||
github.com/otiai10/primes v0.0.0-20180210170552-f6d2a1ba97c4
|
||||
github.com/pkg/errors v0.9.1
|
||||
@@ -19,6 +20,7 @@ require (
|
||||
go.uber.org/zap v1.15.0 // indirect
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
|
||||
golang.org/x/mod v0.3.0 // indirect
|
||||
golang.org/x/text v0.3.0
|
||||
golang.org/x/tools v0.0.0-20200616133436-c1934b75d054 // indirect
|
||||
google.golang.org/protobuf v1.25.0
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||
@@ -27,4 +29,3 @@ require (
|
||||
)
|
||||
|
||||
replace github.com/agl/ed25519 => github.com/binance-chain/edwards25519 v0.0.0-20200305024217-f36fc4b53d43
|
||||
|
||||
|
||||
5
go.sum
5
go.sum
@@ -73,8 +73,12 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
|
||||
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
@@ -149,6 +153,7 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
||||
Reference in New Issue
Block a user