Skip to content

Commit

Permalink
refactor secp256k1 pubkey (#40)
Browse files Browse the repository at this point in the history
Co-authored-by: dustinxie <[email protected]>
  • Loading branch information
Liuhaai and dustinxie authored Apr 11, 2024
1 parent 8498bf1 commit 4a059c1
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 8 deletions.
36 changes: 28 additions & 8 deletions crypto/secp256k1.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type (
}
// secp256k1PubKey implements the SECP256K1 public key
secp256k1PubKey struct {
*ecdsa.PublicKey
raw []byte
}
)

Expand Down Expand Up @@ -72,7 +72,7 @@ func (k *secp256k1PrvKey) EcdsaPrivateKey() interface{} {
// PublicKey returns the public key corresponding to private key
func (k *secp256k1PrvKey) PublicKey() PublicKey {
return &secp256k1PubKey{
PublicKey: &k.PrivateKey.PublicKey,
raw: crypto.FromECDSAPub(&k.PrivateKey.PublicKey),
}
}

Expand All @@ -93,20 +93,35 @@ func (k *secp256k1PrvKey) Zero() {
// PublicKey function
//======================================

var (
secp256k1PubKeyByteLen = (crypto.S256().Params().BitSize + 7) >> 3
)

// newSecp256k1PubKeyFromBytes converts bytes format to PublicKey
func newSecp256k1PubKeyFromBytes(b []byte) (PublicKey, error) {
pk, err := crypto.UnmarshalPubkey(b)
if err != nil {
return nil, err
if !validateP256k1PubkeyBytes(b) {
return nil, ErrPublicKey
}

return &secp256k1PubKey{
PublicKey: pk,
raw: b,
}, nil
}

func validateP256k1PubkeyBytes(data []byte) bool {
if len(data) != 1+2*secp256k1PubKeyByteLen {
return false
}
if data[0] != 4 { // uncompressed form
return false
}

return true
}

// Bytes returns the public key in bytes representation
func (k *secp256k1PubKey) Bytes() []byte {
return crypto.FromECDSAPub(k.PublicKey)
return k.raw
}

// HexString returns the public key in hex string
Expand All @@ -116,7 +131,12 @@ func (k *secp256k1PubKey) HexString() string {

// EcdsaPublicKey returns the embedded ecdsa publick key
func (k *secp256k1PubKey) EcdsaPublicKey() interface{} {
return k.PublicKey
pk, err := crypto.UnmarshalPubkey(k.raw)
if err != nil {
// it should be validated when initialized
panic(err)
}
return pk
}

// Hash is the last 20-byte of keccak hash of public key (X, Y) co-ordinate, same as Ethereum address generation
Expand Down
16 changes: 16 additions & 0 deletions crypto/secp256k1_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,19 @@ func TestSecp256k1(t *testing.T) {
require.Equal("53fbc28faf9a52dfe5f591948a23189e900381b5", hex.EncodeToString(pk.Hash()))

}

func BenchmarkSecp256k1(b *testing.B) {
require := require.New(b)

sk, err := newSecp256k1PrvKey()
require.NoError(err)
defer sk.Zero()
pk := sk.PublicKey()
require.Equal(secp256pubKeyLength, len(pk.Bytes()))
b.ResetTimer()
pkData := pk.Bytes()
for n := 0; n < b.N; n++ {
_, err := newSecp256k1PubKeyFromBytes(pkData)
require.NoError(err)
}
}

0 comments on commit 4a059c1

Please sign in to comment.