diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..4f1799e75 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,42 @@ +name: Release +on: + push: + tags: + - 'v*' + +permissions: + contents: write + +jobs: + release: + name: Publish GitHub Release + runs-on: ubuntu-latest + steps: + + - name: Check out code + uses: actions/checkout@v4 + + - name: Extract changelog section for this version + id: changelog + # Keep a Changelog: pull the `## []` section (from the heading up to the + # next `## [` heading or EOF) matching the pushed tag's version. Fails the build + # when no such section exists so a tag is never published with an empty body. + run: | + version="${GITHUB_REF_NAME#v}" + awk -v ver="$version" ' + $0 ~ "^## \\[" ver "\\]" { in_section = 1 } + in_section && $0 ~ "^## \\[" && $0 !~ "^## \\[" ver "\\]" { exit } + in_section { print } + ' CHANGELOG.md > changelog_section.md + if [ ! -s changelog_section.md ]; then + echo "::error::CHANGELOG.md has no section for version $version (expected a heading like \"## [$version]\"); rename the [Unreleased] section to the versioned heading before tagging." + exit 1 + fi + + - name: Create release + uses: softprops/action-gh-release@v2 + with: + body_path: changelog_section.md + generate_release_notes: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e5902eb2..0a402f60e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ belongs to PR #2 (the base BNB hardening integration) unless it is tagged with a - **PR #5** — removal of EdDSA and ECDSA resharing protocols (stacked on PR #4). - **PR #6** — remaining BNB cryptographic hardening follow-ups (stacked on PR #5). - **PR #7** — signing round-9 decommitment validation and related fixes (stacked on PR #6). +- **PR #19** — protobuf runtime and dependency housekeeping (stacked on PR #7). ### ⚠️ Compatibility — read before upgrading @@ -296,6 +297,10 @@ rejecting input that an honest caller would previously have produced. distinct-generator policy already enforced by DLN and MtA proofs (`crypto/paillier/factor_proof.go`). Honest setups use distinct generators. _Provenance: `threshold-original`, PR #7._ +- **Security dependency updates (PR #19):** `google.golang.org/protobuf` upgraded to v1.33.0 + (the published fix for GHSA-8r3f-844c-mc37 / Dependabot alert #10); `go.mod` now declares a + Go 1.17 minimum toolchain, as required by that runtime. _Provenance: `threshold-original`, + PR #19._ ### Added diff --git a/go.mod b/go.mod index 5030f3f5e..a959a1c55 100644 --- a/go.mod +++ b/go.mod @@ -1,20 +1,28 @@ module github.com/bnb-chain/tss-lib -go 1.16 +go 1.17 require ( github.com/btcsuite/btcd v0.0.0-20190629003639-c26ffa870fd8 github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d - github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-multierror v1.0.0 github.com/ipfs/go-log v0.0.1 - github.com/mattn/go-colorable v0.1.2 // indirect - github.com/opentracing/opentracing-go v1.1.0 // indirect - github.com/otiai10/mint v1.2.4 // indirect github.com/otiai10/primes v0.0.0-20180210170552-f6d2a1ba97c4 github.com/pkg/errors v0.8.1 github.com/stretchr/testify v1.3.0 golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44 + google.golang.org/protobuf v1.33.0 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/gogo/protobuf v1.2.1 // indirect + github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/mattn/go-colorable v0.1.2 // indirect + github.com/mattn/go-isatty v0.0.8 // indirect + github.com/opentracing/opentracing-go v1.1.0 // indirect + github.com/otiai10/mint v1.2.4 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc // indirect golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7 // indirect - google.golang.org/protobuf v1.27.1 ) diff --git a/go.sum b/go.sum index f999801b2..99f58638b 100644 --- a/go.sum +++ b/go.sum @@ -19,9 +19,7 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= @@ -72,10 +70,8 @@ golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= diff --git a/tss/protobuf_compatibility_test.go b/tss/protobuf_compatibility_test.go new file mode 100644 index 000000000..2dd2f8299 --- /dev/null +++ b/tss/protobuf_compatibility_test.go @@ -0,0 +1,90 @@ +// Copyright © 2019 Binance +// +// This file is part of Binance. The full Binance copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package tss_test + +import ( + "bytes" + "encoding/hex" + "math/big" + "testing" + + "github.com/bnb-chain/tss-lib/common" + "github.com/bnb-chain/tss-lib/ecdsa/keygen" + "github.com/bnb-chain/tss-lib/ecdsa/signing" + "github.com/bnb-chain/tss-lib/tss" + "google.golang.org/protobuf/proto" +) + +// These bytes were captured with protobuf v1.27.1 on commit 86bd1a3. Cover +// each generated schema so runtime upgrades preserve the existing encoding. +func TestProtobufBinaryCompatibility(t *testing.T) { + sender := tss.NewPartyID("alice", "A", big.NewInt(1)) + message := signing.NewSignRound3Message(sender, big.NewInt(42)) + for _, tc := range []struct { + name string + message proto.Message + encoded string + }{ + {"signature", &common.SignatureData{Signature: []byte{1, 2}, SignatureRecovery: []byte{0}, R: []byte{3}, S: []byte{4}, M: []byte{0, 5}}, "0a0201021201001a01032201042a020005"}, + {"keygen", &keygen.KGRound2Message2{DeCommitment: [][]byte{{1}, {2, 3}}}, "0a01010a020203"}, + {"signing", message.Content(), "0a012a"}, + {"wrapper", message.WireMsg(), "08011a0d0a05616c6963651201411a010152490a42747970652e676f6f676c65617069732e636f6d2f62696e616e63652e7473736c69622e65636473612e7369676e696e672e5369676e526f756e64334d65737361676512030a012a"}, + } { + t.Run(tc.name, func(t *testing.T) { + want, err := hex.DecodeString(tc.encoded) + if err != nil { + t.Fatal(err) + } + got, err := (proto.MarshalOptions{Deterministic: true}).Marshal(tc.message) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(got, want) { + t.Fatalf("encoding changed: got %x, want %x", got, want) + } + decoded := tc.message.ProtoReflect().Type().New().Interface() + if err := proto.Unmarshal(want, decoded); err != nil { + t.Fatal(err) + } + if !proto.Equal(decoded, tc.message) { + t.Fatal("historical bytes decoded to a different message") + } + }) + } +} + +func TestProtobufWireCompatibility(t *testing.T) { + // The actual transport carries the inner Any, including its type URL. + want, err := hex.DecodeString("0a42747970652e676f6f676c65617069732e636f6d2f62696e616e63652e7473736c69622e65636473612e7369676e696e672e5369676e526f756e64334d65737361676512030a012a") + if err != nil { + t.Fatal(err) + } + sender := tss.NewPartyID("alice", "A", big.NewInt(1)) + sender.Index = 0 + message := signing.NewSignRound3Message(sender, big.NewInt(42)) + wire, routing, err := message.WireBytes() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(wire, want) || routing.From != sender || !routing.IsBroadcast { + t.Fatal("wire encoding or routing changed") + } + parsed, err := tss.ParseWireMessage(want, sender, true) + if err != nil { + t.Fatal(err) + } + if !parsed.ValidateBasic() || !tss.IsSameMessage(message, parsed) { + t.Fatal("historical wire message did not retain its content and routing") + } + roundtrip, _, err := parsed.WireBytes() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(roundtrip, want) { + t.Fatal("historical wire bytes changed after parsing") + } +}