-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into colin/remove-ibc
- Loading branch information
Showing
16 changed files
with
1,269 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
// Package ECDSA implements Cosmos-SDK compatible ECDSA public and private key. The keys | ||
// can be serialized. | ||
package ecdsa |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package ecdsa | ||
|
||
import ( | ||
"crypto/ecdsa" | ||
"crypto/elliptic" | ||
"crypto/rand" | ||
"crypto/sha256" | ||
"fmt" | ||
"math/big" | ||
) | ||
|
||
// GenPrivKey generates a new secp256r1 private key. It uses operating system randomness. | ||
func GenPrivKey(curve elliptic.Curve) (PrivKey, error) { | ||
key, err := ecdsa.GenerateKey(curve, rand.Reader) | ||
if err != nil { | ||
return PrivKey{}, err | ||
} | ||
return PrivKey{*key}, nil | ||
} | ||
|
||
type PrivKey struct { | ||
ecdsa.PrivateKey | ||
} | ||
|
||
// PubKey returns ECDSA public key associated with this private key. | ||
func (sk *PrivKey) PubKey() PubKey { | ||
return PubKey{sk.PublicKey, nil} | ||
} | ||
|
||
// Bytes serialize the private key using big-endian. | ||
func (sk *PrivKey) Bytes() []byte { | ||
if sk == nil { | ||
return nil | ||
} | ||
fieldSize := (sk.Curve.Params().BitSize + 7) / 8 | ||
bz := make([]byte, fieldSize) | ||
sk.D.FillBytes(bz) | ||
return bz | ||
} | ||
|
||
// Sign hashes and signs the message usign ECDSA. Implements SDK PrivKey interface. | ||
func (sk *PrivKey) Sign(msg []byte) ([]byte, error) { | ||
digest := sha256.Sum256(msg) | ||
return sk.PrivateKey.Sign(rand.Reader, digest[:], nil) | ||
} | ||
|
||
// String returns a string representation of the public key based on the curveName. | ||
func (sk *PrivKey) String(name string) string { | ||
return name + "{-}" | ||
} | ||
|
||
// MarshalTo implements proto.Marshaler interface. | ||
func (sk *PrivKey) MarshalTo(dAtA []byte) (int, error) { | ||
bz := sk.Bytes() | ||
copy(dAtA, bz) | ||
return len(bz), nil | ||
} | ||
|
||
// Unmarshal implements proto.Marshaler interface. | ||
func (sk *PrivKey) Unmarshal(bz []byte, curve elliptic.Curve, expectedSize int) error { | ||
if len(bz) != expectedSize { | ||
return fmt.Errorf("wrong ECDSA SK bytes, expecting %d bytes", expectedSize) | ||
} | ||
|
||
sk.Curve = curve | ||
sk.D = new(big.Int).SetBytes(bz) | ||
sk.X, sk.Y = curve.ScalarBaseMult(bz) | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package ecdsa | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/tendermint/tendermint/crypto" | ||
|
||
"github.com/stretchr/testify/suite" | ||
) | ||
|
||
func TestSKSuite(t *testing.T) { | ||
suite.Run(t, new(SKSuite)) | ||
} | ||
|
||
type SKSuite struct{ CommonSuite } | ||
|
||
func (suite *SKSuite) TestString() { | ||
const prefix = "abc" | ||
suite.Require().Equal(prefix+"{-}", suite.sk.String(prefix)) | ||
} | ||
|
||
func (suite *SKSuite) TestPubKey() { | ||
pk := suite.sk.PubKey() | ||
suite.True(suite.sk.PublicKey.Equal(&pk.PublicKey)) | ||
} | ||
|
||
func (suite *SKSuite) Bytes() { | ||
bz := suite.sk.Bytes() | ||
suite.Len(bz, 32) | ||
var sk *PrivKey | ||
suite.Nil(sk.Bytes()) | ||
} | ||
|
||
func (suite *SKSuite) TestMarshal() { | ||
require := suite.Require() | ||
const size = 32 | ||
|
||
var buffer = make([]byte, size) | ||
suite.sk.MarshalTo(buffer) | ||
|
||
var sk = new(PrivKey) | ||
err := sk.Unmarshal(buffer, secp256r1, size) | ||
require.NoError(err) | ||
require.True(sk.Equal(&suite.sk.PrivateKey)) | ||
} | ||
|
||
func (suite *SKSuite) TestSign() { | ||
require := suite.Require() | ||
|
||
msg := crypto.CRandBytes(1000) | ||
sig, err := suite.sk.Sign(msg) | ||
require.NoError(err) | ||
sigCpy := make([]byte, len(sig)) | ||
copy(sigCpy, sig) | ||
require.True(suite.pk.VerifySignature(msg, sigCpy)) | ||
|
||
// Mutate the signature | ||
for i := range sig { | ||
sigCpy[i] ^= byte(i + 1) | ||
require.False(suite.pk.VerifySignature(msg, sigCpy)) | ||
} | ||
|
||
// Mutate the message | ||
msg[1] ^= byte(2) | ||
require.False(suite.pk.VerifySignature(msg, sig)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package ecdsa | ||
|
||
import ( | ||
"crypto/ecdsa" | ||
"crypto/elliptic" | ||
"crypto/sha256" | ||
"encoding/asn1" | ||
"fmt" | ||
"math/big" | ||
|
||
tmcrypto "github.com/tendermint/tendermint/crypto" | ||
|
||
"github.com/cosmos/cosmos-sdk/types/address" | ||
"github.com/cosmos/cosmos-sdk/types/errors" | ||
) | ||
|
||
// signature holds the r and s values of an ECDSA signature. | ||
type signature struct { | ||
R, S *big.Int | ||
} | ||
|
||
type PubKey struct { | ||
ecdsa.PublicKey | ||
|
||
// cache | ||
address tmcrypto.Address | ||
} | ||
|
||
// Address creates an ADR-28 address for ECDSA keys. protoName is a concrete proto structure id. | ||
func (pk *PubKey) Address(protoName string) tmcrypto.Address { | ||
if pk.address == nil { | ||
pk.address = address.Hash(protoName, pk.Bytes()) | ||
} | ||
return pk.address | ||
} | ||
|
||
// Bytes returns the byte representation of the public key using a compressed form | ||
// specified in section 4.3.6 of ANSI X9.62 with first byte being the curve type. | ||
func (pk *PubKey) Bytes() []byte { | ||
if pk == nil { | ||
return nil | ||
} | ||
return elliptic.MarshalCompressed(pk.Curve, pk.X, pk.Y) | ||
} | ||
|
||
// VerifySignature checks if sig is a valid ECDSA signature for msg. | ||
func (pk *PubKey) VerifySignature(msg []byte, sig []byte) bool { | ||
s := new(signature) | ||
if _, err := asn1.Unmarshal(sig, s); err != nil || s == nil { | ||
return false | ||
} | ||
|
||
h := sha256.Sum256(msg) | ||
return ecdsa.Verify(&pk.PublicKey, h[:], s.R, s.S) | ||
} | ||
|
||
// String returns a string representation of the public key based on the curveName. | ||
func (pk *PubKey) String(curveName string) string { | ||
return fmt.Sprintf("%s{%X}", curveName, pk.Bytes()) | ||
} | ||
|
||
// **** Proto Marshaler **** | ||
|
||
// MarshalTo implements proto.Marshaler interface. | ||
func (pk *PubKey) MarshalTo(dAtA []byte) (int, error) { | ||
bz := pk.Bytes() | ||
copy(dAtA, bz) | ||
return len(bz), nil | ||
} | ||
|
||
// Unmarshal implements proto.Marshaler interface. | ||
func (pk *PubKey) Unmarshal(bz []byte, curve elliptic.Curve, expectedSize int) error { | ||
if len(bz) != expectedSize { | ||
return errors.Wrapf(errors.ErrInvalidPubKey, "wrong ECDSA PK bytes, expecting %d bytes, got %d", expectedSize, len(bz)) | ||
} | ||
cpk := ecdsa.PublicKey{Curve: curve} | ||
cpk.X, cpk.Y = elliptic.UnmarshalCompressed(curve, bz) | ||
if cpk.X == nil || cpk.Y == nil { | ||
return errors.Wrapf(errors.ErrInvalidPubKey, "wrong ECDSA PK bytes, unknown curve type: %d", bz[0]) | ||
} | ||
pk.PublicKey = cpk | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package ecdsa | ||
|
||
import ( | ||
"crypto/elliptic" | ||
"encoding/hex" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/suite" | ||
) | ||
|
||
var secp256r1 = elliptic.P256() | ||
|
||
func GenSecp256r1() (PrivKey, error) { | ||
return GenPrivKey(secp256r1) | ||
} | ||
|
||
func TestPKSuite(t *testing.T) { | ||
suite.Run(t, new(PKSuite)) | ||
} | ||
|
||
type CommonSuite struct { | ||
suite.Suite | ||
pk PubKey | ||
sk PrivKey | ||
} | ||
|
||
func (suite *CommonSuite) SetupSuite() { | ||
sk, err := GenSecp256r1() | ||
suite.Require().NoError(err) | ||
suite.sk = sk | ||
suite.pk = sk.PubKey() | ||
} | ||
|
||
type PKSuite struct{ CommonSuite } | ||
|
||
func (suite *PKSuite) TestString() { | ||
assert := suite.Assert() | ||
require := suite.Require() | ||
|
||
prefix := "abc" | ||
pkStr := suite.pk.String(prefix) | ||
assert.Equal(prefix+"{", pkStr[:len(prefix)+1]) | ||
assert.EqualValues('}', pkStr[len(pkStr)-1]) | ||
|
||
bz, err := hex.DecodeString(pkStr[len(prefix)+1 : len(pkStr)-1]) | ||
require.NoError(err) | ||
assert.EqualValues(suite.pk.Bytes(), bz) | ||
} | ||
|
||
func (suite *PKSuite) TestBytes() { | ||
require := suite.Require() | ||
var pk *PubKey | ||
require.Nil(pk.Bytes()) | ||
} | ||
|
||
func (suite *PKSuite) TestMarshal() { | ||
require := suite.Require() | ||
const size = 33 // secp256r1 size | ||
|
||
var buffer = make([]byte, size) | ||
n, err := suite.pk.MarshalTo(buffer) | ||
require.NoError(err) | ||
require.Equal(size, n) | ||
|
||
var pk = new(PubKey) | ||
err = pk.Unmarshal(buffer, secp256r1, size) | ||
require.NoError(err) | ||
require.True(pk.PublicKey.Equal(&suite.pk.PublicKey)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// Package secp256r1 implements Cosmos-SDK compatible ECDSA public and private key. The keys | ||
// can be protobuf serialized and packed in Any. | ||
package secp256r1 | ||
|
||
import ( | ||
"crypto/elliptic" | ||
"fmt" | ||
|
||
codectypes "github.com/cosmos/cosmos-sdk/codec/types" | ||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" | ||
) | ||
|
||
const ( | ||
// fieldSize is the curve domain size. | ||
fieldSize = 32 | ||
pubKeySize = fieldSize + 1 | ||
|
||
name = "secp256r1" | ||
) | ||
|
||
var secp256r1 elliptic.Curve | ||
|
||
func init() { | ||
secp256r1 = elliptic.P256() | ||
// pubKeySize is ceil of field bit size + 1 for the sign | ||
expected := (secp256r1.Params().BitSize + 7) / 8 | ||
if expected != fieldSize { | ||
panic(fmt.Sprintf("Wrong secp256r1 curve fieldSize=%d, expecting=%d", fieldSize, expected)) | ||
} | ||
} | ||
|
||
// RegisterInterfaces adds secp256r1 PubKey to pubkey registry | ||
func RegisterInterfaces(registry codectypes.InterfaceRegistry) { | ||
registry.RegisterImplementations((*cryptotypes.PubKey)(nil), &PubKey{}) | ||
} |
Oops, something went wrong.