Browse Source

Add secp256k1 support

pull/1782/head
Jae Kwon 9 years ago
parent
commit
8b34fd2e51
4 changed files with 202 additions and 11 deletions
  1. +68
    -5
      priv_key.go
  2. +61
    -3
      pub_key.go
  3. +16
    -1
      signature.go
  4. +57
    -2
      signature_test.go

+ 68
- 5
priv_key.go View File

@ -1,6 +1,7 @@
package crypto
import (
secp256k1 "github.com/btcsuite/btcd/btcec"
"github.com/tendermint/ed25519"
"github.com/tendermint/ed25519/extra25519"
. "github.com/tendermint/go-common"
@ -16,13 +17,15 @@ type PrivKey interface {
// Types of PrivKey implementations
const (
PrivKeyTypeEd25519 = byte(0x01)
PrivKeyTypeEd25519 = byte(0x01)
PrivKeyTypeSecp256k1 = byte(0x02)
)
// for wire.readReflect
var _ = wire.RegisterInterface(
struct{ PrivKey }{},
wire.ConcreteType{PrivKeyEd25519{}, PrivKeyTypeEd25519},
wire.ConcreteType{PrivKeySecp256k1{}, PrivKeyTypeSecp256k1},
)
func PrivKeyFromBytes(privKeyBytes []byte) (privKey PrivKey, err error) {
@ -39,8 +42,8 @@ func (privKey PrivKeyEd25519) Bytes() []byte {
return wire.BinaryBytes(struct{ PrivKey }{privKey})
}
func (key PrivKeyEd25519) Sign(msg []byte) Signature {
privKeyBytes := [64]byte(key)
func (privKey PrivKeyEd25519) Sign(msg []byte) Signature {
privKeyBytes := [64]byte(privKey)
signatureBytes := ed25519.Sign(&privKeyBytes, msg)
return SignatureEd25519(*signatureBytes)
}
@ -62,11 +65,11 @@ func (privKey PrivKeyEd25519) String() string {
}
// Deterministically generates new priv-key bytes from key.
func (key PrivKeyEd25519) Generate(index int) PrivKeyEd25519 {
func (privKey PrivKeyEd25519) Generate(index int) PrivKeyEd25519 {
newBytes := wire.BinarySha256(struct {
PrivKey [64]byte
Index int
}{key, index})
}{privKey, index})
var newKey [64]byte
copy(newKey[:], newBytes)
return PrivKeyEd25519(newKey)
@ -88,3 +91,63 @@ func GenPrivKeyEd25519FromSecret(secret []byte) PrivKeyEd25519 {
ed25519.MakePublicKey(privKeyBytes)
return PrivKeyEd25519(*privKeyBytes)
}
//-------------------------------------
// Implements PrivKey
type PrivKeySecp256k1 [32]byte
func (privKey PrivKeySecp256k1) Bytes() []byte {
return wire.BinaryBytes(struct{ PrivKey }{privKey})
}
func (privKey PrivKeySecp256k1) Sign(msg []byte) Signature {
priv__, _ := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKey[:])
sig__, err := priv__.Sign(Sha256(msg))
if err != nil {
PanicSanity(err)
}
return SignatureSecp256k1(sig__.Serialize())
}
func (privKey PrivKeySecp256k1) PubKey() PubKey {
_, pub__ := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKey[:])
pub := [65]byte{}
copy(pub[:], pub__.SerializeUncompressed())
return PubKeySecp256k1(pub)
}
func (privKey PrivKeySecp256k1) String() string {
return Fmt("PrivKeySecp256k1{*****}")
}
/*
// Deterministically generates new priv-key bytes from key.
func (key PrivKeySecp256k1) Generate(index int) PrivKeySecp256k1 {
newBytes := wire.BinarySha256(struct {
PrivKey [64]byte
Index int
}{key, index})
var newKey [64]byte
copy(newKey[:], newBytes)
return PrivKeySecp256k1(newKey)
}
*/
func GenPrivKeySecp256k1() PrivKeySecp256k1 {
privKeyBytes := [32]byte{}
copy(privKeyBytes[:], CRandBytes(32))
priv, _ := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKeyBytes[:])
copy(privKeyBytes[:], priv.Serialize())
return PrivKeySecp256k1(privKeyBytes)
}
// NOTE: secret should be the output of a KDF like bcrypt,
// if it's derived from user input.
func GenPrivKeySecp256k1FromSecret(secret []byte) PrivKeySecp256k1 {
privKey32 := Sha256(secret) // Not Ripemd160 because we want 32 bytes.
priv, _ := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKey32)
privKeyBytes := [32]byte{}
copy(privKeyBytes[:], priv.Serialize())
return PrivKeySecp256k1(privKeyBytes)
}

+ 61
- 3
pub_key.go View File

@ -3,6 +3,7 @@ package crypto
import (
"bytes"
secp256k1 "github.com/btcsuite/btcd/btcec"
"github.com/tendermint/ed25519"
"github.com/tendermint/ed25519/extra25519"
. "github.com/tendermint/go-common"
@ -21,13 +22,15 @@ type PubKey interface {
// Types of PubKey implementations
const (
PubKeyTypeEd25519 = byte(0x01)
PubKeyTypeEd25519 = byte(0x01)
PubKeyTypeSecp256k1 = byte(0x02)
)
// for wire.readReflect
var _ = wire.RegisterInterface(
struct{ PubKey }{},
wire.ConcreteType{PubKeyEd25519{}, PubKeyTypeEd25519},
wire.ConcreteType{PubKeySecp256k1{}, PubKeyTypeSecp256k1},
)
func PubKeyFromBytes(pubKeyBytes []byte) (pubKey PubKey, err error) {
@ -47,7 +50,7 @@ func (pubKey PubKeyEd25519) Address() []byte {
PanicCrisis(*err)
}
// append type byte
encodedPubkey := append([]byte{1}, w.Bytes()...)
encodedPubkey := append([]byte{PubKeyTypeEd25519}, w.Bytes()...)
hasher := ripemd160.New()
hasher.Write(encodedPubkey) // does not error
return hasher.Sum(nil)
@ -57,7 +60,6 @@ func (pubKey PubKeyEd25519) Bytes() []byte {
return wire.BinaryBytes(struct{ PubKey }{pubKey})
}
// TODO: Consider returning a reason for failure, or logging a runtime type mismatch.
func (pubKey PubKeyEd25519) VerifyBytes(msg []byte, sig_ Signature) bool {
sig, ok := sig_.(SignatureEd25519)
if !ok {
@ -96,3 +98,59 @@ func (pubKey PubKeyEd25519) Equals(other PubKey) bool {
return false
}
}
//-------------------------------------
// Implements PubKey
type PubKeySecp256k1 [65]byte
func (pubKey PubKeySecp256k1) Address() []byte {
w, n, err := new(bytes.Buffer), new(int), new(error)
wire.WriteBinary(pubKey[:], w, n, err)
if *err != nil {
PanicCrisis(*err)
}
// append type byte
encodedPubkey := append([]byte{PubKeyTypeSecp256k1}, w.Bytes()...)
hasher := ripemd160.New()
hasher.Write(encodedPubkey) // does not error
return hasher.Sum(nil)
}
func (pubKey PubKeySecp256k1) Bytes() []byte {
return wire.BinaryBytes(struct{ PubKey }{pubKey})
}
func (pubKey PubKeySecp256k1) VerifyBytes(msg []byte, sig_ Signature) bool {
pub__, err := secp256k1.ParsePubKey(pubKey[:], secp256k1.S256())
if err != nil {
return false
}
sig, ok := sig_.(SignatureSecp256k1)
if !ok {
return false
}
sig__, err := secp256k1.ParseDERSignature(sig[:], secp256k1.S256())
if err != nil {
return false
}
return sig__.Verify(Sha256(msg), pub__)
}
func (pubKey PubKeySecp256k1) String() string {
return Fmt("PubKeySecp256k1{%X}", pubKey[:])
}
// Must return the full bytes in hex.
// Used for map keying, etc.
func (pubKey PubKeySecp256k1) KeyString() string {
return Fmt("%X", pubKey[:])
}
func (pubKey PubKeySecp256k1) Equals(other PubKey) bool {
if otherEd, ok := other.(PubKeySecp256k1); ok {
return bytes.Equal(pubKey[:], otherEd[:])
} else {
return false
}
}

+ 16
- 1
signature.go View File

@ -16,13 +16,15 @@ type Signature interface {
// Types of Signature implementations
const (
SignatureTypeEd25519 = byte(0x01)
SignatureTypeEd25519 = byte(0x01)
SignatureTypeSecp256k1 = byte(0x02)
)
// for wire.readReflect
var _ = wire.RegisterInterface(
struct{ Signature }{},
wire.ConcreteType{SignatureEd25519{}, SignatureTypeEd25519},
wire.ConcreteType{SignatureSecp256k1{}, SignatureTypeSecp256k1},
)
//-------------------------------------
@ -37,3 +39,16 @@ func (sig SignatureEd25519) Bytes() []byte {
func (sig SignatureEd25519) IsZero() bool { return len(sig) == 0 }
func (sig SignatureEd25519) String() string { return fmt.Sprintf("/%X.../", Fingerprint(sig[:])) }
//-------------------------------------
// Implements Signature
type SignatureSecp256k1 []byte
func (sig SignatureSecp256k1) Bytes() []byte {
return wire.BinaryBytes(struct{ Signature }{sig})
}
func (sig SignatureSecp256k1) IsZero() bool { return len(sig) == 0 }
func (sig SignatureSecp256k1) String() string { return fmt.Sprintf("/%X.../", Fingerprint(sig[:])) }

+ 57
- 2
signature_test.go View File

@ -8,7 +8,7 @@ import (
"github.com/tendermint/go-wire"
)
func TestSignAndValidate(t *testing.T) {
func TestSignAndValidateEd25519(t *testing.T) {
privKey := GenPrivKeyEd25519()
pubKey := privKey.PubKey()
@ -32,7 +32,31 @@ func TestSignAndValidate(t *testing.T) {
}
}
func TestBinaryDecode(t *testing.T) {
func TestSignAndValidateSecp256k1(t *testing.T) {
privKey := GenPrivKeySecp256k1()
pubKey := privKey.PubKey()
msg := CRandBytes(128)
sig := privKey.Sign(msg)
t.Logf("msg: %X, sig: %X", msg, sig)
// Test the signature
if !pubKey.VerifyBytes(msg, sig) {
t.Errorf("Account message signature verification failed")
}
// Mutate the signature, just one bit.
sigEd := sig.(SignatureSecp256k1)
sigEd[0] ^= byte(0x01)
sig = Signature(sigEd)
if pubKey.VerifyBytes(msg, sig) {
t.Errorf("Account message signature verification should have failed but passed instead")
}
}
func TestBinaryDecodeEd25519(t *testing.T) {
privKey := GenPrivKeyEd25519()
pubKey := privKey.PubKey()
@ -66,3 +90,34 @@ func TestBinaryDecode(t *testing.T) {
t.Errorf("Account message signature verification failed")
}
}
func TestBinaryDecodeSecp256k1(t *testing.T) {
privKey := GenPrivKeySecp256k1()
pubKey := privKey.PubKey()
msg := CRandBytes(128)
sig := privKey.Sign(msg)
t.Logf("msg: %X, sig: %X", msg, sig)
buf, n, err := new(bytes.Buffer), new(int), new(error)
wire.WriteBinary(struct{ Signature }{sig}, buf, n, err)
if *err != nil {
t.Fatalf("Failed to write Signature: %v", err)
}
if buf.Bytes()[0] != SignatureTypeSecp256k1 {
t.Fatalf("Unexpected signature type byte")
}
sigStruct := struct{ Signature }{}
sig2 := wire.ReadBinary(sigStruct, buf, 0, n, err)
if *err != nil {
t.Fatalf("Failed to read Signature: %v", err)
}
// Test the signature
if !pubKey.VerifyBytes(msg, sig2.(struct{ Signature }).Signature.(SignatureSecp256k1)) {
t.Errorf("Account message signature verification failed")
}
}

Loading…
Cancel
Save