Skip to content

Commit

Permalink
Merge pull request cosmos#4 from tendermint/develop
Browse files Browse the repository at this point in the history
go-data support
  • Loading branch information
ebuchman authored Mar 3, 2017
2 parents 4b11d62 + 562b4cc commit 3f47cfa
Show file tree
Hide file tree
Showing 8 changed files with 370 additions and 143 deletions.
9 changes: 9 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.PHONY: docs
REPO:=github.com/tendermint/go-crypto

docs:
@go get github.com/davecheney/godoc2md
godoc2md $(REPO) > README.md

test:
go test ./...
17 changes: 6 additions & 11 deletions armor_test.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,20 @@
package crypto

import (
"bytes"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestSimpleArmor(t *testing.T) {
blockType := "MINT TEST"
data := []byte("somedata")
armorStr := EncodeArmor(blockType, nil, data)
t.Log("Got armor: ", armorStr)

// Decode armorStr and test for equivalence.
blockType2, _, data2, err := DecodeArmor(armorStr)
if err != nil {
t.Error(err)
}
if blockType != blockType2 {
t.Errorf("Expected block type %v but got %v", blockType, blockType2)
}
if !bytes.Equal(data, data2) {
t.Errorf("Expected data %X but got %X", data2, data)
}
require.Nil(t, err, "%+v", err)
assert.Equal(t, blockType, blockType2)
assert.Equal(t, data, data2)
}
112 changes: 112 additions & 0 deletions encode_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package crypto

import (
"strings"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
data "github.com/tendermint/go-data"
)

type byter interface {
Bytes() []byte
}

// go to wire encoding and back
func checkWire(t *testing.T, in byter, reader interface{}, typ byte) {
// test to and from binary
bin, err := data.ToWire(in)
require.Nil(t, err, "%+v", err)
assert.Equal(t, typ, bin[0])
// make sure this is compatible with current (Bytes()) encoding
assert.Equal(t, in.Bytes(), bin)

err = data.FromWire(bin, reader)
require.Nil(t, err, "%+v", err)
}

// go to json encoding and back
func checkJSON(t *testing.T, in interface{}, reader interface{}, typ string) {
// test to and from binary
js, err := data.ToJSON(in)
require.Nil(t, err, "%+v", err)
styp := `"` + typ + `"`
assert.True(t, strings.Contains(string(js), styp))

err = data.FromJSON(js, reader)
require.Nil(t, err, "%+v", err)

// also check text format
text, err := data.ToText(in)
require.Nil(t, err, "%+v", err)
parts := strings.Split(text, ":")
require.Equal(t, 2, len(parts))
// make sure the first part is the typ string
assert.Equal(t, typ, parts[0])
// and the data is also present in the json
assert.True(t, strings.Contains(string(js), parts[1]))
}

func TestKeyEncodings(t *testing.T) {
cases := []struct {
privKey PrivKeyS
keyType byte
keyName string
}{
{
privKey: PrivKeyS{GenPrivKeyEd25519()},
keyType: TypeEd25519,
keyName: NameEd25519,
},
{
privKey: PrivKeyS{GenPrivKeySecp256k1()},
keyType: TypeSecp256k1,
keyName: NameSecp256k1,
},
}

for _, tc := range cases {
// check (de/en)codings of private key
priv2 := PrivKeyS{}
checkWire(t, tc.privKey, &priv2, tc.keyType)
assert.EqualValues(t, tc.privKey, priv2)
priv3 := PrivKeyS{}
checkJSON(t, tc.privKey, &priv3, tc.keyName)
assert.EqualValues(t, tc.privKey, priv3)

// check (de/en)codings of public key
pubKey := PubKeyS{tc.privKey.PubKey()}
pub2 := PubKeyS{}
checkWire(t, pubKey, &pub2, tc.keyType)
assert.EqualValues(t, pubKey, pub2)
pub3 := PubKeyS{}
checkJSON(t, pubKey, &pub3, tc.keyName)
assert.EqualValues(t, pubKey, pub3)
}
}

func toFromJSON(t *testing.T, in interface{}, recvr interface{}) {
js, err := data.ToJSON(in)
require.Nil(t, err, "%+v", err)
err = data.FromJSON(js, recvr)
require.Nil(t, err, "%+v", err)
}

func TestNilEncodings(t *testing.T) {
// make sure sigs are okay with nil
a, b := SignatureS{}, SignatureS{}
toFromJSON(t, a, &b)
assert.EqualValues(t, a, b)

// make sure sigs are okay with nil
c, d := PubKeyS{}, PubKeyS{}
toFromJSON(t, c, &d)
assert.EqualValues(t, c, d)

// make sure sigs are okay with nil
e, f := PrivKeyS{}, PrivKeyS{}
toFromJSON(t, e, &f)
assert.EqualValues(t, e, f)

}
66 changes: 57 additions & 9 deletions priv_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/tendermint/ed25519"
"github.com/tendermint/ed25519/extra25519"
. "github.com/tendermint/go-common"
data "github.com/tendermint/go-data"
"github.com/tendermint/go-wire"
)

Expand All @@ -18,18 +19,43 @@ type PrivKey interface {
Equals(PrivKey) bool
}

// Types of PrivKey implementations
// Types of implementations
const (
PrivKeyTypeEd25519 = byte(0x01)
PrivKeyTypeSecp256k1 = byte(0x02)
TypeEd25519 = byte(0x01)
TypeSecp256k1 = byte(0x02)
NameEd25519 = "ed25519"
NameSecp256k1 = "secp256k1"
)

// for wire.readReflect
var _ = wire.RegisterInterface(
struct{ PrivKey }{},
wire.ConcreteType{PrivKeyEd25519{}, PrivKeyTypeEd25519},
wire.ConcreteType{PrivKeySecp256k1{}, PrivKeyTypeSecp256k1},
)
var privKeyMapper data.Mapper

// register both private key types with go-data (and thus go-wire)
func init() {
privKeyMapper = data.NewMapper(PrivKeyS{}).
RegisterInterface(PrivKeyEd25519{}, NameEd25519, TypeEd25519).
RegisterInterface(PrivKeySecp256k1{}, NameSecp256k1, TypeSecp256k1)
}

// PrivKeyS add json serialization to PrivKey
type PrivKeyS struct {
PrivKey
}

func (p PrivKeyS) MarshalJSON() ([]byte, error) {
return privKeyMapper.ToJSON(p.PrivKey)
}

func (p *PrivKeyS) UnmarshalJSON(data []byte) (err error) {
parsed, err := privKeyMapper.FromJSON(data)
if err == nil && parsed != nil {
p.PrivKey = parsed.(PrivKey)
}
return
}

func (p PrivKeyS) Empty() bool {
return p.PrivKey == nil
}

func PrivKeyFromBytes(privKeyBytes []byte) (privKey PrivKey, err error) {
err = wire.ReadBinaryBytes(privKeyBytes, &privKey)
Expand Down Expand Up @@ -64,6 +90,17 @@ func (privKey PrivKeyEd25519) Equals(other PrivKey) bool {
}
}

func (p PrivKeyEd25519) MarshalJSON() ([]byte, error) {
return data.Encoder.Marshal(p[:])
}

func (p *PrivKeyEd25519) UnmarshalJSON(enc []byte) error {
var ref []byte
err := data.Encoder.Unmarshal(&ref, enc)
copy(p[:], ref)
return err
}

func (privKey PrivKeyEd25519) ToCurve25519() *[32]byte {
keyCurve25519 := new([32]byte)
privKeyBytes := [64]byte(privKey)
Expand Down Expand Up @@ -136,6 +173,17 @@ func (privKey PrivKeySecp256k1) Equals(other PrivKey) bool {
}
}

func (p PrivKeySecp256k1) MarshalJSON() ([]byte, error) {
return data.Encoder.Marshal(p[:])
}

func (p *PrivKeySecp256k1) UnmarshalJSON(enc []byte) error {
var ref []byte
err := data.Encoder.Unmarshal(&ref, enc)
copy(p[:], ref)
return err
}

func (privKey PrivKeySecp256k1) String() string {
return Fmt("PrivKeySecp256k1{*****}")
}
Expand Down
83 changes: 67 additions & 16 deletions pub_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/tendermint/ed25519"
"github.com/tendermint/ed25519/extra25519"
. "github.com/tendermint/go-common"
data "github.com/tendermint/go-data"
"github.com/tendermint/go-wire"
"golang.org/x/crypto/ripemd160"
)
Expand All @@ -20,18 +21,35 @@ type PubKey interface {
Equals(PubKey) bool
}

// Types of PubKey implementations
const (
PubKeyTypeEd25519 = byte(0x01)
PubKeyTypeSecp256k1 = byte(0x02)
)
var pubKeyMapper data.Mapper

// for wire.readReflect
var _ = wire.RegisterInterface(
struct{ PubKey }{},
wire.ConcreteType{PubKeyEd25519{}, PubKeyTypeEd25519},
wire.ConcreteType{PubKeySecp256k1{}, PubKeyTypeSecp256k1},
)
// register both public key types with go-data (and thus go-wire)
func init() {
pubKeyMapper = data.NewMapper(PubKeyS{}).
RegisterInterface(PubKeyEd25519{}, NameEd25519, TypeEd25519).
RegisterInterface(PubKeySecp256k1{}, NameSecp256k1, TypeSecp256k1)
}

// PubKeyS add json serialization to PubKey
type PubKeyS struct {
PubKey
}

func (p PubKeyS) MarshalJSON() ([]byte, error) {
return pubKeyMapper.ToJSON(p.PubKey)
}

func (p *PubKeyS) UnmarshalJSON(data []byte) (err error) {
parsed, err := pubKeyMapper.FromJSON(data)
if err == nil && parsed != nil {
p.PubKey = parsed.(PubKey)
}
return
}

func (p PubKeyS) Empty() bool {
return p.PubKey == nil
}

func PubKeyFromBytes(pubKeyBytes []byte) (pubKey PubKey, err error) {
err = wire.ReadBinaryBytes(pubKeyBytes, &pubKey)
Expand All @@ -50,7 +68,7 @@ func (pubKey PubKeyEd25519) Address() []byte {
PanicCrisis(*err)
}
// append type byte
encodedPubkey := append([]byte{PubKeyTypeEd25519}, w.Bytes()...)
encodedPubkey := append([]byte{TypeEd25519}, w.Bytes()...)
hasher := ripemd160.New()
hasher.Write(encodedPubkey) // does not error
return hasher.Sum(nil)
Expand All @@ -61,6 +79,11 @@ func (pubKey PubKeyEd25519) Bytes() []byte {
}

func (pubKey PubKeyEd25519) VerifyBytes(msg []byte, sig_ Signature) bool {
// unwrap if needed
if wrap, ok := sig_.(SignatureS); ok {
sig_ = wrap.Signature
}
// make sure we use the same algorithm to sign
sig, ok := sig_.(SignatureEd25519)
if !ok {
return false
Expand All @@ -70,6 +93,17 @@ func (pubKey PubKeyEd25519) VerifyBytes(msg []byte, sig_ Signature) bool {
return ed25519.Verify(&pubKeyBytes, msg, &sigBytes)
}

func (p PubKeyEd25519) MarshalJSON() ([]byte, error) {
return data.Encoder.Marshal(p[:])
}

func (p *PubKeyEd25519) UnmarshalJSON(enc []byte) error {
var ref []byte
err := data.Encoder.Unmarshal(&ref, enc)
copy(p[:], ref)
return err
}

// For use with golang/crypto/nacl/box
// If error, returns nil.
func (pubKey PubKeyEd25519) ToCurve25519() *[32]byte {
Expand Down Expand Up @@ -111,7 +145,7 @@ func (pubKey PubKeySecp256k1) Address() []byte {
PanicCrisis(*err)
}
// append type byte
encodedPubkey := append([]byte{PubKeyTypeSecp256k1}, w.Bytes()...)
encodedPubkey := append([]byte{TypeSecp256k1}, w.Bytes()...)
hasher := ripemd160.New()
hasher.Write(encodedPubkey) // does not error
return hasher.Sum(nil)
Expand All @@ -122,21 +156,38 @@ func (pubKey PubKeySecp256k1) Bytes() []byte {
}

func (pubKey PubKeySecp256k1) VerifyBytes(msg []byte, sig_ Signature) bool {
pub__, err := secp256k1.ParsePubKey(append([]byte{0x04}, pubKey[:]...), secp256k1.S256())
if err != nil {
return false
// unwrap if needed
if wrap, ok := sig_.(SignatureS); ok {
sig_ = wrap.Signature
}
// and assert same algorithm to sign and verify
sig, ok := sig_.(SignatureSecp256k1)
if !ok {
return false
}

pub__, err := secp256k1.ParsePubKey(append([]byte{0x04}, pubKey[:]...), secp256k1.S256())
if err != nil {
return false
}
sig__, err := secp256k1.ParseDERSignature(sig[:], secp256k1.S256())
if err != nil {
return false
}
return sig__.Verify(Sha256(msg), pub__)
}

func (p PubKeySecp256k1) MarshalJSON() ([]byte, error) {
return data.Encoder.Marshal(p[:])
}

func (p *PubKeySecp256k1) UnmarshalJSON(enc []byte) error {
var ref []byte
err := data.Encoder.Unmarshal(&ref, enc)
copy(p[:], ref)
return err
}

func (pubKey PubKeySecp256k1) String() string {
return Fmt("PubKeySecp256k1{%X}", pubKey[:])
}
Expand Down
Loading

0 comments on commit 3f47cfa

Please sign in to comment.