Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: secp256k1 public key constant time #18026

Merged
merged 64 commits into from
Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
c32ca65
added bench test for ed25519 key
bizk Aug 15, 2023
d54017c
added multisig test
bizk Aug 15, 2023
ffc39eb
added hashihg for basic ADR28 address on ed25519
bizk Aug 15, 2023
1770ef3
ran lint fix
bizk Aug 16, 2023
546dd4e
merge with master
bizk Aug 16, 2023
5f20b8c
Refactor tests
bizk Aug 16, 2023
d057344
merge
bizk Aug 17, 2023
71d6a6d
Merge branch 'main' of github.com:Zondax/cosmos-sdk into zondax/featu…
bizk Sep 19, 2023
f46939e
empty commit to re run actions
bizk Sep 19, 2023
c5872a0
empty commit to re run actions
bizk Sep 19, 2023
b148bd3
Merge branch 'main' of github.com:Zondax/cosmos-sdk into zondax/featu…
bizk Sep 29, 2023
e6d38b7
Merge branch 'main' of github.com:Zondax/cosmos-sdk into …
bizk Sep 29, 2023
0655ad1
added go constant time secp256k1
bizk Oct 6, 2023
09ce545
added constant time pub key implementation and tests
bizk Oct 9, 2023
2af7ad3
Merge branch 'main' of github.com:Zondax/cosmos-sdk into zondax/featu…
bizk Oct 9, 2023
1b18936
reverted changes and deleted optimization to make code fully constant
bizk Oct 9, 2023
f0e1c06
removed tidy code
bizk Oct 9, 2023
ae93077
Added changelog.md
bizk Oct 9, 2023
4ebca65
cleanup
bizk Oct 9, 2023
b6a0494
cleanup
bizk Oct 9, 2023
e5f98c5
go lint fix
bizk Oct 9, 2023
0586436
gofumpt files
bizk Oct 10, 2023
6416425
added fix on deprecated package
bizk Oct 10, 2023
8898092
suggestion by linter
bizk Oct 10, 2023
70c604c
ran gci
bizk Oct 10, 2023
5e96e6b
gci fix
bizk Oct 10, 2023
6a70994
returned file back to how it was
bizk Oct 10, 2023
d1fb6d0
Merge branch 'main' into feature/secp256k1constant
bizk Oct 10, 2023
d6519f4
Merge branch 'main' into feature/secp256k1constant
bizk Oct 17, 2023
c89049c
Merge branch 'main' into feature/secp256k1constant
bizk Oct 25, 2023
9b2fb97
switched secp point generation library
bizk Oct 26, 2023
8f2685c
Merge branch 'feature/secp256k1constant' of github.com:Zondax/cosmos-…
bizk Oct 26, 2023
f3462b9
switched secp priv key generation to constant time implementation and…
bizk Oct 26, 2023
b18542c
Merge branch 'main' into feature/secp256k1constant
bizk Oct 26, 2023
cc501e3
added missing go.mod files
bizk Oct 30, 2023
6b3c859
Merge branch 'main' into feature/secp256k1constant
bizk Oct 30, 2023
68154f5
solved issue with go.mod files
bizk Oct 30, 2023
54318a5
fixed small tests
bizk Oct 31, 2023
c25aa08
Merge branch 'feature/secp256k1constant' of github.com:Zondax/cosmos-…
bizk Oct 31, 2023
a8508ed
fixed hd and ledger tests, also added missing go.mod
bizk Oct 31, 2023
16883d1
fixed add_key test
bizk Oct 31, 2023
465f1e6
lint-fix
bizk Nov 1, 2023
7389cd2
fixed issues
bizk Nov 1, 2023
397c526
gcied add.go file
bizk Nov 1, 2023
f8be857
Merge branch 'main' into feature/secp256k1constant
bizk Nov 1, 2023
4eb2fbf
gcied modified file
bizk Nov 1, 2023
87e1ecf
Merge branch 'feature/secp256k1constant' of github.com:Zondax/cosmos-…
bizk Nov 1, 2023
84db0b4
lint fix
bizk Nov 1, 2023
1485810
Merge branch 'main' into feature/secp256k1constant
bizk Nov 1, 2023
4cb92c4
Merge branch 'main' into feature/secp256k1constant
bizk Nov 2, 2023
9f15cfd
ran go mod script
bizk Nov 7, 2023
8ea5da5
rollback internal secp key generation on test
bizk Nov 7, 2023
b6e6cbe
Merge branch 'main' into feature/secp256k1constant
bizk Nov 7, 2023
ef99726
lint fix
bizk Nov 7, 2023
01c79d5
Merge branch 'main' into feature/secp256k1constant
bizk Nov 7, 2023
c2d5fa9
Merge branch 'main' into feature/secp256k1constant
bizk Nov 7, 2023
10b8a8a
Merge branch 'main' into feature/secp256k1constant
bizk Nov 9, 2023
0b29d5e
fixed tests
bizk Nov 13, 2023
8bc73ee
merge
bizk Nov 21, 2023
9b04f9e
Merge branch 'main' into feature/secp256k1constant
bizk Nov 28, 2023
eeb4fc7
fixed changelog
bizk Nov 28, 2023
7989412
Merge branch 'main' into feature/secp256k1constant
bizk Nov 29, 2023
2217d1b
Merge branch 'main' into feature/secp256k1constant
bizk Dec 4, 2023
0c101fa
removed unused import
bizk Dec 4, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (types) [#17670](https://github.com/cosmos/cosmos-sdk/pull/17670) Use `ctx.CometInfo` in place of `ctx.VoteInfos`
* [#17733](https://github.com/cosmos/cosmos-sdk/pull/17733) Ensure `buf export` exports all proto dependencies
* [#18204](https://github.com/cosmos/cosmos-sdk/pull/18204) Use streaming json parser to parse chain-id from genesis file.
bizk marked this conversation as resolved.
Show resolved Hide resolved
* (crypto/keys) [#7051](https://github.com/cosmos/cosmos-sdk/issues/7051) Made public key generation constant time on `secp256k1`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The entry for pull request #14372 contains a potential typo: "antehandle" may be intended to be "ante handle" or "antehandler". Please verify the correct terminology and update accordingly.

bizk marked this conversation as resolved.
Show resolved Hide resolved

### Bug Fixes

Expand Down
2 changes: 1 addition & 1 deletion crypto/keys/secp256k1/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
func BenchmarkKeyGeneration(b *testing.B) {
b.ReportAllocs()
benchmarkKeygenWrapper := func(reader io.Reader) types.PrivKey {
priv := genPrivKey(reader)
priv := genPrivKey()
return &PrivKey{Key: priv}
}
benchmarking.BenchmarkKeyGeneration(b, benchmarkKeygenWrapper)
Expand Down
7 changes: 5 additions & 2 deletions crypto/keys/secp256k1/internal/secp256k1/secp256_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ package secp256k1
import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"encoding/hex"
"io"
Expand All @@ -24,7 +23,11 @@ func generateKeyPair() (pubkey, privkey []byte) {
if err != nil {
panic(err)
}
pubkey = elliptic.Marshal(S256(), key.X, key.Y) //nolint:staticcheck // crypto will be refactored soon.
publicKeyEcdh, err := key.PublicKey.ECDH()
if err != nil {
panic(err)
}
pubkey = publicKeyEcdh.Bytes()
privkey = make([]byte, 32)
blob := key.D.Bytes()
copy(privkey[32-len(blob):], blob)
Expand Down
35 changes: 13 additions & 22 deletions crypto/keys/secp256k1/secp256k1.go
bizk marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"crypto/sha256"
"crypto/subtle"
"fmt"
"io"
"gitlab.com/yawning/secp256k1-voi/secec"
"math/big"

"github.com/cometbft/cometbft/crypto"
Expand Down Expand Up @@ -39,9 +39,12 @@ func (privKey *PrivKey) Bytes() []byte {
// PubKey performs the point-scalar multiplication from the privKey on the
// generator point to get the pubkey.
func (privKey *PrivKey) PubKey() cryptotypes.PubKey {
pubkeyObject := secp256k1.PrivKeyFromBytes(privKey.Key).PubKey()
pk := pubkeyObject.SerializeCompressed()
return &PubKey{Key: pk}
privateKeyObject, err := secec.NewPrivateKey(privKey.Key)
if err != nil {
panic(err)
}
bizk marked this conversation as resolved.
Show resolved Hide resolved

return &PubKey{Key: privateKeyObject.PublicKey().CompressedBytes()}
bizk marked this conversation as resolved.
Show resolved Hide resolved
}

// Equals - you probably don't need to use this.
Expand Down Expand Up @@ -84,29 +87,17 @@ func (privKey *PrivKey) UnmarshalAminoJSON(bz []byte) error {
// GenPrivKey generates a new ECDSA private key on curve secp256k1 private key.
// It uses OS randomness to generate the private key.
func GenPrivKey() *PrivKey {
return &PrivKey{Key: genPrivKey(crypto.CReader())}
return &PrivKey{Key: genPrivKey()}
}

// genPrivKey generates a new secp256k1 private key using the provided reader.
func genPrivKey(rand io.Reader) []byte {
var privKeyBytes [PrivKeySize]byte
d := new(big.Int)
for {
privKeyBytes = [PrivKeySize]byte{}
_, err := io.ReadFull(rand, privKeyBytes[:])
if err != nil {
panic(err)
}

d.SetBytes(privKeyBytes[:])
// break if we found a valid point (i.e. > 0 and < N == curverOrder)
isValidFieldElement := 0 < d.Sign() && d.Cmp(secp256k1.S256().N) < 0
if isValidFieldElement {
break
}
func genPrivKey() []byte {
privateKeyObject, err := secec.GenerateKey()
if err != nil {
panic(err)
}
bizk marked this conversation as resolved.
Show resolved Hide resolved

return privKeyBytes[:]
return privateKeyObject.Bytes()
bizk marked this conversation as resolved.
Show resolved Hide resolved
}

var one = new(big.Int).SetInt64(1)
Expand Down
7 changes: 2 additions & 5 deletions crypto/keys/secp256k1/secp256k1_internal_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package secp256k1

import (
"bytes"
"math/big"
"testing"

Expand All @@ -22,20 +21,18 @@ func Test_genPrivKey(t *testing.T) {
notSoRand []byte
shouldPanic bool
}{
{"empty bytes (panics because 1st 32 bytes are zero and 0 is not a valid field element)", empty, true},
{"curve order: N", secp.S256().N.Bytes(), true},
bizk marked this conversation as resolved.
Show resolved Hide resolved
{"valid because 0 < 1 < N", validOne, false},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
if tt.shouldPanic {
require.Panics(t, func() {
genPrivKey(bytes.NewReader(tt.notSoRand))
genPrivKey()
})
return
}
got := genPrivKey(bytes.NewReader(tt.notSoRand))
got := genPrivKey()
fe := new(big.Int).SetBytes(got)
require.True(t, fe.Cmp(secp.S256().N) < 0)
require.True(t, fe.Sign() > 0)
Expand Down
27 changes: 22 additions & 5 deletions crypto/keys/secp256k1/secp256k1_nocgo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ package secp256k1
import (
"testing"

secp256k1 "github.com/decred/dcrd/dcrec/secp256k1/v4"
secp256k1_dcrd "github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/stretchr/testify/require"
)

Expand All @@ -19,18 +19,18 @@ func TestSignatureVerificationAndRejectUpperS(t *testing.T) {
priv := GenPrivKey()
sigStr, err := priv.Sign(msg)
require.NoError(t, err)
var r secp256k1.ModNScalar
var r secp256k1_dcrd.ModNScalar
r.SetByteSlice(sigStr[:32])
var s secp256k1.ModNScalar
var s secp256k1_dcrd.ModNScalar
s.SetByteSlice(sigStr[32:64])
require.False(t, s.IsOverHalfOrder())

pub := priv.PubKey()
require.True(t, pub.VerifySignature(msg, sigStr))

// malleate:
var S256 secp256k1.ModNScalar
S256.SetByteSlice(secp256k1.S256().N.Bytes())
var S256 secp256k1_dcrd.ModNScalar
S256.SetByteSlice(secp256k1_dcrd.S256().N.Bytes())
s.Negate().Add(&S256)
require.True(t, s.IsOverHalfOrder())

Expand All @@ -46,3 +46,20 @@ func TestSignatureVerificationAndRejectUpperS(t *testing.T) {
)
}
}

func TestConstantTimePubKeyGeneration(t *testing.T) {
for i := 0; i < 500; i++ {
pk := GenPrivKey().PubKey()
require.NotNil(t, pk)
}
}

// Legacy generation code
func TestNonConstantTimePubKeyGeneration(t *testing.T) {
for i := 0; i < 500; i++ {
privKey := GenPrivKey()
nonConstantTimePk := secp256k1_dcrd.PrivKeyFromBytes(privKey.Key).PubKey().SerializeCompressed() // Legacy functionability from pubkey
pk := &PubKey{Key: nonConstantTimePk}
require.NotNil(t, pk)
}
}
11 changes: 11 additions & 0 deletions crypto/keys/secp256k1/secp256k1_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -450,3 +450,14 @@ func TestMarshalAmino_BackwardsCompatibility(t *testing.T) {
})
}
}

func TestLegacyKeyGenerationAgainstConstantTime(t *testing.T) {
privKey := secp256k1.GenPrivKey()

pubKey := privKey.PubKey()

nonConstantTimePk := secp.PrivKeyFromBytes(privKey.Key).PubKey().SerializeCompressed() // Legacy functionability from pubkey
legacyPubKey := &secp256k1.PubKey{Key: nonConstantTimePk}

require.Equal(t, legacyPubKey, pubKey)
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ require (
github.com/spf13/viper v1.17.0
github.com/stretchr/testify v1.8.4
github.com/tendermint/go-amino v0.16.0
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b
golang.org/x/crypto v0.14.0
golang.org/x/exp v0.0.0-20231006140011-7918f672742d
golang.org/x/sync v0.4.0
Expand Down Expand Up @@ -148,6 +149,7 @@ require (
github.com/tidwall/btree v1.7.0 // indirect
github.com/zondax/hid v0.9.2 // indirect
github.com/zondax/ledger-go v0.14.3 // indirect
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect
go.etcd.io/bbolt v1.3.7 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/net v0.17.0 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,10 @@ github.com/zondax/hid v0.9.2 h1:WCJFnEDMiqGF64nlZz28E9qLVZ0KSJ7xpc5DLEyma2U=
github.com/zondax/hid v0.9.2/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM=
github.com/zondax/ledger-go v0.14.3 h1:wEpJt2CEcBJ428md/5MgSLsXLBos98sBOyxNmCjfUCw=
github.com/zondax/ledger-go v0.14.3/go.mod h1:IKKaoxupuB43g4NxeQmbLXv7T9AlQyie1UpHb342ycI=
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b h1:CzigHMRySiX3drau9C6Q5CAbNIApmLdat5jPMqChvDA=
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b/go.mod h1:/y/V339mxv2sZmYYR64O07VuCpdNZqCTwO8ZcouTMI8=
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 h1:qwDnMxjkyLmAFgcfgTnfJrmYKWhHnci3GjDqcZp1M3Q=
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02/go.mod h1:JTnUj0mpYiAsuZLmKjTx/ex3AtMowcCgnE7YNyCEP0I=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
Expand Down
Loading