Skip to content

Commit a18f0b1

Browse files
Enable secp256r1 (#8786)
* enable secp256r1 in antehandlers * Add sig verification benchamrk to find a sigverify fee * adjust the gas fee * enable secp256r1 in antehandlers * Add sig verification benchamrk to find a sigverify fee * adjust the gas fee * Update the secp256r1 fee factor * Update changelog * regenerate docs
1 parent 72fb8b3 commit a18f0b1

File tree

8 files changed

+92
-37
lines changed

8 files changed

+92
-37
lines changed

CHANGELOG.md

+5-4
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,14 @@ Ref: https://keepachangelog.com/en/1.0.0/
3838

3939
## Features
4040

41-
* [\#8559](https://github.com/cosmos/cosmos-sdk/pull/8559) Adding Protobuf compatible secp256r1 ECDSA signatures.
41+
* [\#8559](https://github.com/cosmos/cosmos-sdk/pull/8559) Added Protobuf compatible secp256r1 ECDSA signatures.
42+
* [\#8786](https://github.com/cosmos/cosmos-sdk/pull/8786) Enabled secp256r1 in x/auth.
4243

4344
### Client Breaking Changes
4445

4546
* [\#8363](https://github.com/cosmos/cosmos-sdk/pull/8363) Addresses no longer have a fixed 20-byte length. From the SDK modules' point of view, any 1-255 bytes-long byte array is a valid address.
4647
* [\#8346](https://github.com/cosmos/cosmos-sdk/pull/8346) All CLI `tx` commands generate ServiceMsgs by default. Graceful Amino support has been added to ServiceMsgs to support signing legacy Msgs.
47-
* (crypto/ed25519) [\#8690] Adopt zip1215 ed2559 verification rules.
48+
* (crypto/ed25519) [\#8690] Adopt zip1215 ed2559 verification rules.
4849

4950
### API Breaking Changes
5051

@@ -55,7 +56,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
5556
* (x/distribution) [\#8473](https://github.com/cosmos/cosmos-sdk/pull/8473) On genesis init, if the distribution module account balance, coming from bank module state, does not match the one in distribution module state, the initialization will panic.
5657
* (client/keys) [\#8500](https://github.com/cosmos/cosmos-sdk/pull/8500) `InfoImporter` interface is removed from legacy keybase.
5758
* [\#8629](https://github.com/cosmos/cosmos-sdk/pull/8629) Deprecated `SetFullFundraiserPath` from `Config` in favor of `SetPurpose` and `SetCoinType`.
58-
* (x/upgrade) [\#8673](https://github.com/cosmos/cosmos-sdk/pull/8673) Remove IBC logic from x/upgrade. Deprecates IBC fields in an Upgrade Plan. IBC upgrade logic moved to 02-client and an IBC UpgradeProposal is added.
59+
* (x/upgrade) [\#8673](https://github.com/cosmos/cosmos-sdk/pull/8673) Remove IBC logic from x/upgrade. Deprecates IBC fields in an Upgrade Plan. IBC upgrade logic moved to 02-client and an IBC UpgradeProposal is added.
5960
* (x/bank) [\#8517](https://github.com/cosmos/cosmos-sdk/pull/8517) `SupplyI` interface and `Supply` are removed and uses `sdk.Coins` for supply tracking
6061

6162
### State Machine Breaking
@@ -72,7 +73,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
7273

7374
* (x/bank) [\#8614](https://github.com/cosmos/cosmos-sdk/issues/8614) Add `Name` and `Symbol` fields to denom metadata
7475
* (x/auth) [\#8522](https://github.com/cosmos/cosmos-sdk/pull/8522) Allow to query all stored accounts
75-
* (x/ibc) [\#7949](https://github.com/cosmos/cosmos-sdk/issues/7949) Standardized channel `Acknowledgement` moved to its own file. Codec registration redundancy removed.
76+
* (x/ibc) [\#7949](https://github.com/cosmos/cosmos-sdk/issues/7949) Standardized channel `Acknowledgement` moved to its own file. Codec registration redundancy removed.
7677
* (crypto/types) [\#8600](https://github.com/cosmos/cosmos-sdk/pull/8600) `CompactBitArray`: optimize the `NumTrueBitsBefore` method and add an `Equal` method.
7778
* (x/ibc) [\#8624](https://github.com/cosmos/cosmos-sdk/pull/8624) Emit full header in IBC UpdateClient message.
7879

crypto/keys/secp256r1/keys.pb.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/core/proto-docs.md

+1-18
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@
8080
- [Output](#cosmos.bank.v1beta1.Output)
8181
- [Params](#cosmos.bank.v1beta1.Params)
8282
- [SendEnabled](#cosmos.bank.v1beta1.SendEnabled)
83-
- [Supply](#cosmos.bank.v1beta1.Supply)
8483

8584
- [cosmos/bank/v1beta1/genesis.proto](#cosmos/bank/v1beta1/genesis.proto)
8685
- [Balance](#cosmos.bank.v1beta1.Balance)
@@ -1561,22 +1560,6 @@ sendable).
15611560

15621561

15631562

1564-
1565-
<a name="cosmos.bank.v1beta1.Supply"></a>
1566-
1567-
### Supply
1568-
Supply represents a struct that passively keeps track of the total supply
1569-
amounts in the network.
1570-
1571-
1572-
| Field | Type | Label | Description |
1573-
| ----- | ---- | ----- | ----------- |
1574-
| `total` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | |
1575-
1576-
1577-
1578-
1579-
15801563
<!-- end messages -->
15811564

15821565
<!-- end enums -->
@@ -2946,7 +2929,7 @@ PubKey defines a secp256r1 ECDSA public key.
29462929

29472930
| Field | Type | Label | Description |
29482931
| ----- | ---- | ----- | ----------- |
2949-
| `key` | [bytes](#bytes) | | Point on secp256r1 curve in a compressed representation as specified in section 4.3.6 of ANSI X9.62. |
2932+
| `key` | [bytes](#bytes) | | Point on secp256r1 curve in a compressed representation as specified in section 4.3.6 of ANSI X9.62: https://webstore.ansi.org/standards/ascx9/ansix9621998 |
29502933

29512934

29522935

testutil/testdata/tx.go

+11
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import (
44
"encoding/json"
55

66
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
7+
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1"
78
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
89
sdk "github.com/cosmos/cosmos-sdk/types"
10+
"github.com/stretchr/testify/require"
911
)
1012

1113
// KeyTestPubAddr generates a new secp256k1 keypair.
@@ -16,6 +18,15 @@ func KeyTestPubAddr() (cryptotypes.PrivKey, cryptotypes.PubKey, sdk.AccAddress)
1618
return key, pub, addr
1719
}
1820

21+
// KeyTestPubAddr generates a new secp256r1 keypair.
22+
func KeyTestPubAddrSecp256R1(require *require.Assertions) (cryptotypes.PrivKey, cryptotypes.PubKey, sdk.AccAddress) {
23+
key, err := secp256r1.GenPrivKey()
24+
require.NoError(err)
25+
pub := key.PubKey()
26+
addr := sdk.AccAddress(pub.Address())
27+
return key, pub, addr
28+
}
29+
1930
// NewTestFeeAmount is a test fee amount.
2031
func NewTestFeeAmount() sdk.Coins {
2132
return sdk.NewCoins(sdk.NewInt64Coin("atom", 150))

x/auth/ante/sigverify.go

+5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
99
kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
1010
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
11+
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1"
1112
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
1213
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
1314
sdk "github.com/cosmos/cosmos-sdk/types"
@@ -368,6 +369,10 @@ func DefaultSigVerificationGasConsumer(
368369
meter.ConsumeGas(params.SigVerifyCostSecp256k1, "ante verify: secp256k1")
369370
return nil
370371

372+
case *secp256r1.PubKey:
373+
meter.ConsumeGas(params.SigVerifyCostSecp256r1(), "ante verify: secp256r1")
374+
return nil
375+
371376
case multisig.PubKey:
372377
multisignature, ok := sig.Data.(*signing.MultiSignatureData)
373378
if !ok {
+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package ante_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
tmcrypto "github.com/tendermint/tendermint/crypto"
8+
9+
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
10+
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1"
11+
)
12+
13+
// This benchmark is used to asses the ante.Secp256k1ToR1GasFactor value
14+
func BenchmarkSig(b *testing.B) {
15+
require := require.New(b)
16+
msg := tmcrypto.CRandBytes(1000)
17+
18+
skK := secp256k1.GenPrivKey()
19+
pkK := skK.PubKey()
20+
skR, _ := secp256r1.GenPrivKey()
21+
pkR := skR.PubKey()
22+
23+
sigK, err := skK.Sign(msg)
24+
require.NoError(err)
25+
sigR, err := skR.Sign(msg)
26+
require.NoError(err)
27+
b.ResetTimer()
28+
29+
b.Run("secp256k1", func(b *testing.B) {
30+
for i := 0; i < b.N; i++ {
31+
ok := pkK.VerifySignature(msg, sigK)
32+
require.True(ok)
33+
}
34+
})
35+
36+
b.Run("secp256r1", func(b *testing.B) {
37+
for i := 0; i < b.N; i++ {
38+
ok := pkR.VerifySignature(msg, sigR)
39+
require.True(ok)
40+
}
41+
})
42+
}

x/auth/ante/sigverify_test.go

+17-14
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
99
kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
1010
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
11+
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1"
1112
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
1213
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
1314
"github.com/cosmos/cosmos-sdk/simapp"
@@ -21,12 +22,13 @@ import (
2122

2223
func (suite *AnteTestSuite) TestSetPubKey() {
2324
suite.SetupTest(true) // setup
25+
require := suite.Require()
2426
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
2527

2628
// keys and addresses
2729
priv1, pub1, addr1 := testdata.KeyTestPubAddr()
2830
priv2, pub2, addr2 := testdata.KeyTestPubAddr()
29-
priv3, pub3, addr3 := testdata.KeyTestPubAddr()
31+
priv3, pub3, addr3 := testdata.KeyTestPubAddrSecp256R1(require)
3032

3133
addrs := []sdk.AccAddress{addr1, addr2, addr3}
3234
pubs := []cryptotypes.PubKey{pub1, pub2, pub3}
@@ -35,32 +37,30 @@ func (suite *AnteTestSuite) TestSetPubKey() {
3537
// set accounts and create msg for each address
3638
for i, addr := range addrs {
3739
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr)
38-
suite.Require().NoError(acc.SetAccountNumber(uint64(i)))
40+
require.NoError(acc.SetAccountNumber(uint64(i)))
3941
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
4042
msgs[i] = testdata.NewTestMsg(addr)
4143
}
42-
suite.Require().NoError(suite.txBuilder.SetMsgs(msgs...))
43-
44-
feeAmount := testdata.NewTestFeeAmount()
45-
gasLimit := testdata.NewTestGasLimit()
46-
suite.txBuilder.SetFeeAmount(feeAmount)
47-
suite.txBuilder.SetGasLimit(gasLimit)
44+
require.NoError(suite.txBuilder.SetMsgs(msgs...))
45+
suite.txBuilder.SetFeeAmount(testdata.NewTestFeeAmount())
46+
suite.txBuilder.SetGasLimit(testdata.NewTestGasLimit())
4847

4948
privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{0, 1, 2}, []uint64{0, 0, 0}
5049
tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
51-
suite.Require().NoError(err)
50+
require.NoError(err)
5251

5352
spkd := ante.NewSetPubKeyDecorator(suite.app.AccountKeeper)
5453
antehandler := sdk.ChainAnteDecorators(spkd)
5554

5655
ctx, err := antehandler(suite.ctx, tx, false)
57-
suite.Require().Nil(err)
56+
require.NoError(err)
5857

5958
// Require that all accounts have pubkey set after Decorator runs
6059
for i, addr := range addrs {
6160
pk, err := suite.app.AccountKeeper.GetPubKey(ctx, addr)
62-
suite.Require().Nil(err, "Error on retrieving pubkey from account")
63-
suite.Require().Equal(pubs[i], pk, "Pubkey retrieved from account is unexpected")
61+
require.NoError(err, "Error on retrieving pubkey from account")
62+
require.True(pubs[i].Equals(pk),
63+
"Wrong Pubkey retrieved from AccountKeeper, idx=%d\nexpected=%s\n got=%s", i, pubs[i], pk)
6464
}
6565
}
6666

@@ -69,6 +69,8 @@ func (suite *AnteTestSuite) TestConsumeSignatureVerificationGas() {
6969
msg := []byte{1, 2, 3, 4}
7070
cdc := simapp.MakeTestEncodingConfig().Amino
7171

72+
p := types.DefaultParams()
73+
skR1, _ := secp256r1.GenPrivKey()
7274
pkSet1, sigSet1 := generatePubKeysAndSignatures(5, msg, false)
7375
multisigKey1 := kmultisig.NewLegacyAminoPubKey(2, pkSet1)
7476
multisignature1 := multisig.NewMultisig(len(pkSet1))
@@ -93,8 +95,9 @@ func (suite *AnteTestSuite) TestConsumeSignatureVerificationGas() {
9395
gasConsumed uint64
9496
shouldErr bool
9597
}{
96-
{"PubKeyEd25519", args{sdk.NewInfiniteGasMeter(), nil, ed25519.GenPrivKey().PubKey(), params}, types.DefaultSigVerifyCostED25519, true},
97-
{"PubKeySecp256k1", args{sdk.NewInfiniteGasMeter(), nil, secp256k1.GenPrivKey().PubKey(), params}, types.DefaultSigVerifyCostSecp256k1, false},
98+
{"PubKeyEd25519", args{sdk.NewInfiniteGasMeter(), nil, ed25519.GenPrivKey().PubKey(), params}, p.SigVerifyCostED25519, true},
99+
{"PubKeySecp256k1", args{sdk.NewInfiniteGasMeter(), nil, secp256k1.GenPrivKey().PubKey(), params}, p.SigVerifyCostSecp256k1, false},
100+
{"PubKeySecp256r1", args{sdk.NewInfiniteGasMeter(), nil, skR1.PubKey(), params}, p.SigVerifyCostSecp256r1(), false},
98101
{"Multisig", args{sdk.NewInfiniteGasMeter(), multisignature1, multisigKey1, params}, expectedCost1, false},
99102
{"unknown key", args{sdk.NewInfiniteGasMeter(), nil, nil, params}, 0, true},
100103
}

x/auth/types/params.go

+10
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,16 @@ func DefaultParams() Params {
6969
}
7070
}
7171

72+
// SigVerifyCostSecp256r1 returns gas fee of secp256r1 signature verification.
73+
// Set by benchmarking current implementation:
74+
// BenchmarkSig/secp256k1 4334 277167 ns/op 4128 B/op 79 allocs/op
75+
// BenchmarkSig/secp256r1 10000 108769 ns/op 1672 B/op 33 allocs/op
76+
// Based on the results above secp256k1 is 2.7x is slwer. However we propose to discount it
77+
// because we are we don't compare the cgo implementation of secp256k1, which is faster.
78+
func (p Params) SigVerifyCostSecp256r1() uint64 {
79+
return p.SigVerifyCostSecp256k1 / 2
80+
}
81+
7282
// String implements the stringer interface.
7383
func (p Params) String() string {
7484
out, _ := yaml.Marshal(p)

0 commit comments

Comments
 (0)