diff --git a/priv_key.go b/priv_key.go index e9b43caa..2806e24f 100644 --- a/priv_key.go +++ b/priv_key.go @@ -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) +} diff --git a/pub_key.go b/pub_key.go index 6da13077..1162a1ef 100644 --- a/pub_key.go +++ b/pub_key.go @@ -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 + } +} diff --git a/signature.go b/signature.go index 8eafab7c..e4921ccf 100644 --- a/signature.go +++ b/signature.go @@ -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[:])) } diff --git a/signature_test.go b/signature_test.go index e4e72e48..88c490f3 100644 --- a/signature_test.go +++ b/signature_test.go @@ -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") + } +}