From a3324cc97bf90b49437eb4cf1da3c7733259b62d Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Sun, 9 Apr 2017 00:32:54 -0700 Subject: [PATCH] Cleanup; Implement .Wrap() --- crypto.go | 9 ++++ embed_test.go | 102 +++++++++++++++------------------------------- encode_test.go | 4 +- priv_key.go | 91 ++++++++++++++++++----------------------- pub_key.go | 85 ++++++++++++++++++-------------------- signature.go | 99 +++++++++++++++++++++----------------------- signature_test.go | 24 +++++------ 7 files changed, 181 insertions(+), 233 deletions(-) create mode 100644 crypto.go diff --git a/crypto.go b/crypto.go new file mode 100644 index 000000000..d9caf1ad9 --- /dev/null +++ b/crypto.go @@ -0,0 +1,9 @@ +package crypto + +// Types of implementations +const ( + TypeEd25519 = byte(0x01) + TypeSecp256k1 = byte(0x02) + NameEd25519 = "ed25519" + NameSecp256k1 = "secp256k1" +) diff --git a/embed_test.go b/embed_test.go index eda72b438..6ebba893c 100644 --- a/embed_test.go +++ b/embed_test.go @@ -9,50 +9,13 @@ import ( data "github.com/tendermint/go-data" ) -type Foo struct { - Name string -} - -func (f Foo) Greet() string { - return "Foo: " + f.Name -} - -type Bar struct { - Age int -} - -func (b Bar) Greet() string { - return fmt.Sprintf("Bar #%d", b.Age) +type PubName struct { + PubNameInner } type PubNameInner interface { - Greet() string -} - -type privNameInner interface { - Greet() string -} - -type Greeter interface { - Greet() string -} - -var ( - pubNameMapper, privNameMapper data.Mapper -) - -// register both public key types with go-data (and thus go-wire) -func init() { - pubNameMapper = data.NewMapper(PubName{}). - RegisterImplementation(Foo{}, "foo", 1). - RegisterImplementation(Bar{}, "bar", 2) - privNameMapper = data.NewMapper(PrivName{}). - RegisterImplementation(Foo{}, "foo", 1). - RegisterImplementation(Bar{}, "bar", 2) -} - -type PubName struct { - PubNameInner + AssertIsPubNameInner() + String() string } func (p PubName) MarshalJSON() ([]byte, error) { @@ -67,62 +30,61 @@ func (p *PubName) UnmarshalJSON(data []byte) error { return err } -type PrivName struct { - privNameInner -} +var pubNameMapper = data.NewMapper(PubName{}). + RegisterImplementation(PubNameFoo{}, "foo", 1). + RegisterImplementation(PubNameBar{}, "bar", 2) -func (p PrivName) MarshalJSON() ([]byte, error) { - return privNameMapper.ToJSON(p.privNameInner) +func (f PubNameFoo) AssertIsPubNameInner() {} +func (f PubNameBar) AssertIsPubNameInner() {} + +//---------------------------------------- + +type PubNameFoo struct { + Name string } -func (p *PrivName) UnmarshalJSON(data []byte) error { - parsed, err := privNameMapper.FromJSON(data) - if err == nil && parsed != nil { - p.privNameInner = parsed.(privNameInner) - } - return err +func (f PubNameFoo) String() string { return "Foo: " + f.Name } + +type PubNameBar struct { + Age int } +func (b PubNameBar) String() string { return fmt.Sprintf("Bar #%d", b.Age) } + +//---------------------------------------- + // TestEncodeDemo tries the various strategies to encode the objects func TestEncodeDemo(t *testing.T) { assert, require := assert.New(t), require.New(t) - // assert := assert.New(t) - // require := require.New(t) cases := []struct { - in, out Greeter + in, out PubNameInner expected string }{ - {PubName{Foo{"pub-foo"}}, &PubName{}, "Foo: pub-foo"}, - {PubName{Bar{7}}, &PubName{}, "Bar #7"}, - - // Note these fail - if you can figure a solution here, I'll buy you a beer :) - // (ebuchman is right, you must either break the reflection system, or modify go-wire) - // but such a mod would let us make REALLY sure that no one could construct like this - - // {PrivName{Foo{"priv-foo"}}, &PrivName{}, "Foo: priv-foo"}, - // {PrivName{Bar{9}}, &PrivName{}, "Bar #9"}, + {PubName{PubNameFoo{"pub-foo"}}, &PubName{}, "Foo: pub-foo"}, + {PubName{PubNameBar{7}}, &PubName{}, "Bar #7"}, } for i, tc := range cases { - // make sure it is proper to start - require.Equal(tc.expected, tc.in.Greet()) - // now, try to encode as binary + // Make sure it is proper to start + require.Equal(tc.expected, tc.in.String()) + + // Try to encode as binary b, err := data.ToWire(tc.in) if assert.Nil(err, "%d: %#v", i, tc.in) { err := data.FromWire(b, tc.out) if assert.Nil(err) { - assert.Equal(tc.expected, tc.out.Greet()) + assert.Equal(tc.expected, tc.out.String()) } } - // try to encode it as json + // Try to encode it as json j, err := data.ToJSON(tc.in) if assert.Nil(err, "%d: %#v", i, tc.in) { err := data.FromJSON(j, tc.out) if assert.Nil(err) { - assert.Equal(tc.expected, tc.out.Greet()) + assert.Equal(tc.expected, tc.out.String()) } } } diff --git a/encode_test.go b/encode_test.go index 9a8e5902c..2d709b943 100644 --- a/encode_test.go +++ b/encode_test.go @@ -69,12 +69,12 @@ func TestKeyEncodings(t *testing.T) { keyName string }{ { - privKey: WrapPrivKey(GenPrivKeyEd25519()), + privKey: GenPrivKeyEd25519().Wrap(), keyType: TypeEd25519, keyName: NameEd25519, }, { - privKey: WrapPrivKey(GenPrivKeySecp256k1()), + privKey: GenPrivKeySecp256k1().Wrap(), keyType: TypeSecp256k1, keyName: NameSecp256k1, }, diff --git a/priv_key.go b/priv_key.go index d21bdf458..74d5b5a3e 100644 --- a/priv_key.go +++ b/priv_key.go @@ -11,50 +11,38 @@ import ( "github.com/tendermint/go-wire" ) -/* -DO NOT USE this interface. +func PrivKeyFromBytes(privKeyBytes []byte) (privKey PrivKey, err error) { + err = wire.ReadBinaryBytes(privKeyBytes, &privKey) + return +} -It is public by necessity but should never be used directly -outside of this package. +//---------------------------------------- -Only use the PrivKey, never the PrivKeyInner -*/ +type PrivKey struct { + PrivKeyInner `json:"unwrap"` +} + +// DO NOT USE THIS INTERFACE. +// You probably want to use PubKey type PrivKeyInner interface { + AssertIsPrivKeyInner() Bytes() []byte Sign(msg []byte) Signature PubKey() PubKey Equals(PrivKey) bool + Wrap() PrivKey } -// Types of implementations -const ( - TypeEd25519 = byte(0x01) - TypeSecp256k1 = byte(0x02) - NameEd25519 = "ed25519" - NameSecp256k1 = "secp256k1" -) - -var privKeyMapper data.Mapper - -// register both private key types with go-data (and thus go-wire) -func init() { - privKeyMapper = data.NewMapper(PrivKey{}). - RegisterImplementation(PrivKeyEd25519{}, NameEd25519, TypeEd25519). - RegisterImplementation(PrivKeySecp256k1{}, NameSecp256k1, TypeSecp256k1) -} - -// PrivKey should be used instead of an interface in all external packages -// unless you demand a concrete implementation, then use that directly. -type PrivKey struct { - PrivKeyInner `json:"unwrap"` +func (p PrivKey) MarshalJSON() ([]byte, error) { + return privKeyMapper.ToJSON(p.PrivKeyInner) } -// WrapPrivKey goes from concrete implementation to "interface" struct -func WrapPrivKey(pk PrivKeyInner) PrivKey { - if wrap, ok := pk.(PrivKey); ok { - pk = wrap.Unwrap() +func (p *PrivKey) UnmarshalJSON(data []byte) (err error) { + parsed, err := privKeyMapper.FromJSON(data) + if err == nil && parsed != nil { + p.PrivKeyInner = parsed.(PrivKeyInner) } - return PrivKey{pk} + return } // Unwrap recovers the concrete interface safely (regardless of levels of embeds) @@ -66,32 +54,21 @@ func (p PrivKey) Unwrap() PrivKeyInner { return pk } -func (p PrivKey) MarshalJSON() ([]byte, error) { - return privKeyMapper.ToJSON(p.PrivKeyInner) -} - -func (p *PrivKey) UnmarshalJSON(data []byte) (err error) { - parsed, err := privKeyMapper.FromJSON(data) - if err == nil && parsed != nil { - p.PrivKeyInner = parsed.(PrivKeyInner) - } - return -} - func (p PrivKey) Empty() bool { return p.PrivKeyInner == nil } -func PrivKeyFromBytes(privKeyBytes []byte) (privKey PrivKey, err error) { - err = wire.ReadBinaryBytes(privKeyBytes, &privKey) - return -} +var privKeyMapper = data.NewMapper(PrivKey{}). + RegisterImplementation(PrivKeyEd25519{}, NameEd25519, TypeEd25519). + RegisterImplementation(PrivKeySecp256k1{}, NameSecp256k1, TypeSecp256k1) //------------------------------------- // Implements PrivKey type PrivKeyEd25519 [64]byte +func (privKey PrivKeyEd25519) AssertIsPrivKeyInner() {} + func (privKey PrivKeyEd25519) Bytes() []byte { return wire.BinaryBytes(PrivKey{privKey}) } @@ -99,13 +76,13 @@ func (privKey PrivKeyEd25519) Bytes() []byte { func (privKey PrivKeyEd25519) Sign(msg []byte) Signature { privKeyBytes := [64]byte(privKey) signatureBytes := ed25519.Sign(&privKeyBytes, msg) - return WrapSignature(SignatureEd25519(*signatureBytes)) + return SignatureEd25519(*signatureBytes).Wrap() } func (privKey PrivKeyEd25519) PubKey() PubKey { privKeyBytes := [64]byte(privKey) pubBytes := *ed25519.MakePublicKey(&privKeyBytes) - return WrapPubKey(PubKeyEd25519(pubBytes)) + return PubKeyEd25519(pubBytes).Wrap() } func (privKey PrivKeyEd25519) Equals(other PrivKey) bool { @@ -149,6 +126,10 @@ func (privKey PrivKeyEd25519) Generate(index int) PrivKeyEd25519 { return PrivKeyEd25519(newKey) } +func (privKey PrivKeyEd25519) Wrap() PrivKey { + return PrivKey{privKey} +} + func GenPrivKeyEd25519() PrivKeyEd25519 { privKeyBytes := new([64]byte) copy(privKeyBytes[:32], CRandBytes(32)) @@ -171,6 +152,8 @@ func GenPrivKeyEd25519FromSecret(secret []byte) PrivKeyEd25519 { // Implements PrivKey type PrivKeySecp256k1 [32]byte +func (privKey PrivKeySecp256k1) AssertIsPrivKeyInner() {} + func (privKey PrivKeySecp256k1) Bytes() []byte { return wire.BinaryBytes(PrivKey{privKey}) } @@ -181,14 +164,14 @@ func (privKey PrivKeySecp256k1) Sign(msg []byte) Signature { if err != nil { PanicSanity(err) } - return WrapSignature(SignatureSecp256k1(sig__.Serialize())) + return SignatureSecp256k1(sig__.Serialize()).Wrap() } func (privKey PrivKeySecp256k1) PubKey() PubKey { _, pub__ := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKey[:]) var pub PubKeySecp256k1 copy(pub[:], pub__.SerializeCompressed()) - return WrapPubKey(pub) + return pub.Wrap() } func (privKey PrivKeySecp256k1) Equals(other PrivKey) bool { @@ -214,6 +197,10 @@ func (privKey PrivKeySecp256k1) String() string { return Fmt("PrivKeySecp256k1{*****}") } +func (privKey PrivKeySecp256k1) Wrap() PrivKey { + return PrivKey{privKey} +} + /* // Deterministically generates new priv-key bytes from key. func (key PrivKeySecp256k1) Generate(index int) PrivKeySecp256k1 { diff --git a/pub_key.go b/pub_key.go index a763688fe..e6567d347 100644 --- a/pub_key.go +++ b/pub_key.go @@ -13,80 +13,65 @@ import ( "golang.org/x/crypto/ripemd160" ) -/* -DO NOT USE this interface. +func PubKeyFromBytes(pubKeyBytes []byte) (pubKey PubKey, err error) { + err = wire.ReadBinaryBytes(pubKeyBytes, &pubKey) + return +} -It is public by necessity but should never be used directly -outside of this package. +//---------------------------------------- -Only use the PubKey, never the PubKeyInner -*/ +type PubKey struct { + PubKeyInner `json:"unwrap"` +} + +// DO NOT USE THIS INTERFACE. +// You probably want to use PubKey type PubKeyInner interface { + AssertIsPubKeyInner() Address() []byte Bytes() []byte KeyString() string VerifyBytes(msg []byte, sig Signature) bool Equals(PubKey) bool + Wrap() PubKey } -var pubKeyMapper data.Mapper - -// register both public key types with go-data (and thus go-wire) -func init() { - pubKeyMapper = data.NewMapper(PubKey{}). - RegisterImplementation(PubKeyEd25519{}, NameEd25519, TypeEd25519). - RegisterImplementation(PubKeySecp256k1{}, NameSecp256k1, TypeSecp256k1) +func (pk PubKey) MarshalJSON() ([]byte, error) { + return pubKeyMapper.ToJSON(pk.PubKeyInner) } -// PubKey should be used instead of an interface in all external packages -// unless you demand a concrete implementation, then use that directly. -type PubKey struct { - PubKeyInner `json:"unwrap"` -} - -// WrapPubKey goes from concrete implementation to "interface" struct -func WrapPubKey(pk PubKeyInner) PubKey { - if wrap, ok := pk.(PubKey); ok { - pk = wrap.Unwrap() +func (pk *PubKey) UnmarshalJSON(data []byte) (err error) { + parsed, err := pubKeyMapper.FromJSON(data) + if err == nil && parsed != nil { + pk.PubKeyInner = parsed.(PubKeyInner) } - return PubKey{pk} + return } // Unwrap recovers the concrete interface safely (regardless of levels of embeds) -func (p PubKey) Unwrap() PubKeyInner { - pk := p.PubKeyInner - for wrap, ok := pk.(PubKey); ok; wrap, ok = pk.(PubKey) { - pk = wrap.PubKeyInner - } - return pk -} - -func (p PubKey) MarshalJSON() ([]byte, error) { - return pubKeyMapper.ToJSON(p.PubKeyInner) -} - -func (p *PubKey) UnmarshalJSON(data []byte) (err error) { - parsed, err := pubKeyMapper.FromJSON(data) - if err == nil && parsed != nil { - p.PubKeyInner = parsed.(PubKeyInner) +func (pk PubKey) Unwrap() PubKeyInner { + pkI := pk.PubKeyInner + for wrap, ok := pkI.(PubKey); ok; wrap, ok = pkI.(PubKey) { + pkI = wrap.PubKeyInner } - return + return pkI } func (p PubKey) Empty() bool { return p.PubKeyInner == nil } -func PubKeyFromBytes(pubKeyBytes []byte) (pubKey PubKey, err error) { - err = wire.ReadBinaryBytes(pubKeyBytes, &pubKey) - return -} +var pubKeyMapper = data.NewMapper(PubKey{}). + RegisterImplementation(PubKeyEd25519{}, NameEd25519, TypeEd25519). + RegisterImplementation(PubKeySecp256k1{}, NameSecp256k1, TypeSecp256k1) //------------------------------------- // Implements PubKeyInner type PubKeyEd25519 [32]byte +func (pubKey PubKeyEd25519) AssertIsPubKeyInner() {} + func (pubKey PubKeyEd25519) Address() []byte { w, n, err := new(bytes.Buffer), new(int), new(error) wire.WriteBinary(pubKey[:], w, n, err) @@ -155,6 +140,10 @@ func (pubKey PubKeyEd25519) Equals(other PubKey) bool { } } +func (pubKey PubKeyEd25519) Wrap() PubKey { + return PubKey{pubKey} +} + //------------------------------------- // Implements PubKey. @@ -162,6 +151,8 @@ func (pubKey PubKeyEd25519) Equals(other PubKey) bool { // prefixed with 0x02 or 0x03, depending on the y-cord. type PubKeySecp256k1 [33]byte +func (pubKey PubKeySecp256k1) AssertIsPubKeyInner() {} + // Implements Bitcoin style addresses: RIPEMD160(SHA256(pubkey)) func (pubKey PubKeySecp256k1) Address() []byte { hasherSHA256 := sha256.New() @@ -223,3 +214,7 @@ func (pubKey PubKeySecp256k1) Equals(other PubKey) bool { return false } } + +func (pubKey PubKeySecp256k1) Wrap() PubKey { + return PubKey{pubKey} +} diff --git a/signature.go b/signature.go index bb3e8f11b..66c9a8a27 100644 --- a/signature.go +++ b/signature.go @@ -9,79 +9,64 @@ import ( "github.com/tendermint/go-wire" ) -/* -DO NOT USE this interface. +func SignatureFromBytes(sigBytes []byte) (sig Signature, err error) { + err = wire.ReadBinaryBytes(sigBytes, &sig) + return +} -It is public by necessity but should never be used directly -outside of this package. +//---------------------------------------- -Only use the Signature, never the SignatureInner -*/ +type Signature struct { + SignatureInner `json:"unwrap"` +} + +// DO NOT USE THIS INTERFACE. +// You probably want to use Signature. type SignatureInner interface { + AssertIsSignatureInner() Bytes() []byte IsZero() bool String() string Equals(Signature) bool + Wrap() Signature } -var sigMapper data.Mapper - -// register both public key types with go-data (and thus go-wire) -func init() { - sigMapper = data.NewMapper(Signature{}). - RegisterImplementation(SignatureEd25519{}, NameEd25519, TypeEd25519). - RegisterImplementation(SignatureSecp256k1{}, NameSecp256k1, TypeSecp256k1) +func (sig Signature) MarshalJSON() ([]byte, error) { + return sigMapper.ToJSON(sig.SignatureInner) } -// Signature should be used instead of an interface in all external packages -// unless you demand a concrete implementation, then use that directly. -type Signature struct { - SignatureInner `json:"unwrap"` -} - -// WrapSignature goes from concrete implementation to "interface" struct -func WrapSignature(pk SignatureInner) Signature { - if wrap, ok := pk.(Signature); ok { - pk = wrap.Unwrap() +func (sig *Signature) UnmarshalJSON(data []byte) (err error) { + parsed, err := sigMapper.FromJSON(data) + if err == nil && parsed != nil { + sig.SignatureInner = parsed.(SignatureInner) } - return Signature{pk} + return } // Unwrap recovers the concrete interface safely (regardless of levels of embeds) -func (p Signature) Unwrap() SignatureInner { - pk := p.SignatureInner +func (sig Signature) Unwrap() SignatureInner { + pk := sig.SignatureInner for wrap, ok := pk.(Signature); ok; wrap, ok = pk.(Signature) { pk = wrap.SignatureInner } return pk } -func (p Signature) MarshalJSON() ([]byte, error) { - return sigMapper.ToJSON(p.SignatureInner) -} - -func (p *Signature) UnmarshalJSON(data []byte) (err error) { - parsed, err := sigMapper.FromJSON(data) - if err == nil && parsed != nil { - p.SignatureInner = parsed.(SignatureInner) - } - return +func (sig Signature) Empty() bool { + return sig.SignatureInner == nil } -func (p Signature) Empty() bool { - return p.SignatureInner == nil -} - -func SignatureFromBytes(sigBytes []byte) (sig Signature, err error) { - err = wire.ReadBinaryBytes(sigBytes, &sig) - return -} +var sigMapper = data.NewMapper(Signature{}). + RegisterImplementation(SignatureEd25519{}, NameEd25519, TypeEd25519). + RegisterImplementation(SignatureSecp256k1{}, NameSecp256k1, TypeSecp256k1) //------------------------------------- // Implements Signature type SignatureEd25519 [64]byte +func (sig SignatureEd25519) AssertIsSignatureInner() {} + func (sig SignatureEd25519) Bytes() []byte { return wire.BinaryBytes(Signature{sig}) } @@ -98,22 +83,28 @@ func (sig SignatureEd25519) Equals(other Signature) bool { } } -func (p SignatureEd25519) MarshalJSON() ([]byte, error) { - return data.Encoder.Marshal(p[:]) +func (sig SignatureEd25519) MarshalJSON() ([]byte, error) { + return data.Encoder.Marshal(sig[:]) } -func (p *SignatureEd25519) UnmarshalJSON(enc []byte) error { +func (sig *SignatureEd25519) UnmarshalJSON(enc []byte) error { var ref []byte err := data.Encoder.Unmarshal(&ref, enc) - copy(p[:], ref) + copy(sig[:], ref) return err } +func (sig SignatureEd25519) Wrap() Signature { + return Signature{sig} +} + //------------------------------------- // Implements Signature type SignatureSecp256k1 []byte +func (sig SignatureSecp256k1) AssertIsSignatureInner() {} + func (sig SignatureSecp256k1) Bytes() []byte { return wire.BinaryBytes(Signature{sig}) } @@ -129,10 +120,14 @@ func (sig SignatureSecp256k1) Equals(other Signature) bool { return false } } -func (p SignatureSecp256k1) MarshalJSON() ([]byte, error) { - return data.Encoder.Marshal(p) +func (sig SignatureSecp256k1) MarshalJSON() ([]byte, error) { + return data.Encoder.Marshal(sig) +} + +func (sig *SignatureSecp256k1) UnmarshalJSON(enc []byte) error { + return data.Encoder.Unmarshal((*[]byte)(sig), enc) } -func (p *SignatureSecp256k1) UnmarshalJSON(enc []byte) error { - return data.Encoder.Unmarshal((*[]byte)(p), enc) +func (sig SignatureSecp256k1) Wrap() Signature { + return Signature{sig} } diff --git a/signature_test.go b/signature_test.go index 92fed906d..93aa17279 100644 --- a/signature_test.go +++ b/signature_test.go @@ -24,7 +24,7 @@ func TestSignAndValidateEd25519(t *testing.T) { // Mutate the signature, just one bit. sigEd := sig.Unwrap().(SignatureEd25519) sigEd[7] ^= byte(0x01) - sig = WrapSignature(sigEd) + sig = sigEd.Wrap() assert.False(t, pubKey.VerifyBytes(msg, sig)) } @@ -41,7 +41,7 @@ func TestSignAndValidateSecp256k1(t *testing.T) { // Mutate the signature, just one bit. sigEd := sig.Unwrap().(SignatureSecp256k1) sigEd[3] ^= byte(0x01) - sig = WrapSignature(sigEd) + sig = sigEd.Wrap() assert.False(t, pubKey.VerifyBytes(msg, sig)) } @@ -54,13 +54,13 @@ func TestSignatureEncodings(t *testing.T) { sigName string }{ { - privKey: WrapPrivKey(GenPrivKeyEd25519()), + privKey: GenPrivKeyEd25519().Wrap(), sigSize: ed25519.SignatureSize, sigType: TypeEd25519, sigName: NameEd25519, }, { - privKey: WrapPrivKey(GenPrivKeySecp256k1()), + privKey: GenPrivKeySecp256k1().Wrap(), sigSize: 0, // unknown sigType: TypeSecp256k1, sigName: NameSecp256k1, @@ -119,10 +119,10 @@ func TestWrapping(t *testing.T) { // do some wrapping pubs := []PubKey{ - WrapPubKey(nil), - WrapPubKey(pub), - WrapPubKey(WrapPubKey(WrapPubKey(WrapPubKey(pub)))), - WrapPubKey(PubKey{PubKey{PubKey{pub}}}), + PubKey{nil}, + pub.Wrap(), + pub.Wrap().Wrap().Wrap(), + PubKey{PubKey{PubKey{pub}}}.Wrap(), } for _, p := range pubs { _, ok := p.PubKeyInner.(PubKey) @@ -130,10 +130,10 @@ func TestWrapping(t *testing.T) { } sigs := []Signature{ - WrapSignature(nil), - WrapSignature(sig), - WrapSignature(WrapSignature(WrapSignature(WrapSignature(sig)))), - WrapSignature(Signature{Signature{Signature{sig}}}), + Signature{nil}, + sig.Wrap(), + sig.Wrap().Wrap().Wrap(), + Signature{Signature{Signature{sig}}}.Wrap(), } for _, s := range sigs { _, ok := s.SignatureInner.(Signature)