diff --git a/go.mod b/go.mod index 563fa92..0ed02cb 100644 --- a/go.mod +++ b/go.mod @@ -6,15 +6,7 @@ require ( github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d github.com/cosmos/ledger-go v0.9.1 github.com/davecgh/go-spew v1.1.1 // indirect - github.com/fortytw2/leaktest v1.3.0 // indirect - github.com/go-kit/kit v0.6.0 // indirect - github.com/go-logfmt/logfmt v0.4.0 // indirect - github.com/go-stack/stack v1.8.0 // indirect - github.com/gogo/protobuf v1.1.1 // indirect github.com/pkg/errors v0.8.1 // indirect github.com/stretchr/testify v1.3.0 - github.com/tendermint/tendermint v0.29.1 github.com/zondax/hid v0.9.0 // indirect - golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 // indirect - golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc // indirect ) diff --git a/go.sum b/go.sum index 59511ce..d78f3e7 100644 --- a/go.sum +++ b/go.sum @@ -14,25 +14,13 @@ github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= -github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/go-kit/kit v0.6.0 h1:wTifptAGIyIuir4bRyN4h7+kAa2a4eepLYVmRe5qqQ8= -github.com/go-kit/kit v0.6.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -43,20 +31,14 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/tendermint/tendermint v0.29.1 h1:9QwXNxtxgfekONjEBvnZp2g3mQH/fS5QiUyEXo7QOGs= -github.com/tendermint/tendermint v0.29.1/go.mod h1:ymcPyWblXCplCPQjbOYbrF1fWnpslATMVqiGgWbZrlc= github.com/zondax/hid v0.9.0 h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8= github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 h1:mKdxBk7AujPs8kU4m80U72y/zjbZ3UcXC7dClwKbUI0= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc h1:WiYx1rIFmx8c0mXAFtv5D/mHyKe1+jmuP7PViuwqwuQ= -golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= diff --git a/user_app.go b/user_app.go index c2826cf..40eda06 100644 --- a/user_app.go +++ b/user_app.go @@ -20,6 +20,7 @@ import ( "fmt" "math" + "github.com/btcsuite/btcd/btcec" "github.com/cosmos/ledger-go" ) @@ -108,11 +109,13 @@ func (ledger *LedgerCosmos) GetVersion() (*VersionInfo, error) { } // SignSECP256K1 signs a transaction using Cosmos user app +// this command requires user confirmation in the device func (ledger *LedgerCosmos) SignSECP256K1(bip32Path []uint32, transaction []byte) ([]byte, error) { return ledger.sign(userINSSignSECP256K1, bip32Path, transaction) } -// GetPublicKeySECP256K1 retrieves the public key for the corresponding bip32 derivation path +// GetPublicKeySECP256K1 retrieves the public key for the corresponding bip32 derivation path (compressed) +// this command DOES NOT require user confirmation in the device func (ledger *LedgerCosmos) GetPublicKeySECP256K1(bip32Path []uint32) ([]byte, error) { pathBytes, err := GetBip32bytes(bip32Path, 3) if err != nil { @@ -131,7 +134,11 @@ func (ledger *LedgerCosmos) GetPublicKeySECP256K1(bip32Path []uint32) ([]byte, e return nil, fmt.Errorf("invalid response") } - return response, nil + cmp, err := btcec.ParsePubKey(response[:], btcec.S256()) + if err != nil { + return nil, err + } + return cmp.SerializeCompressed(), nil } func validHRPByte(b byte) bool { @@ -139,44 +146,8 @@ func validHRPByte(b byte) bool { return b >= 33 && b <= 126 } -// ShowAddressSECP256K1 shows the address for the corresponding bip32 derivation path -func (ledger *LedgerCosmos) ShowAddressSECP256K1(bip32Path []uint32, hrp string) error { - if len(hrp) > 83 { - return fmt.Errorf("hrp len should be <10") - } - - hrpBytes := []byte(hrp) - for _, b := range hrpBytes { - if !validHRPByte(b) { - return fmt.Errorf("all characters in the HRP must be in the [33, 126] range") - } - } - - // Check that app is at least 1.1.0 - requiredVersion := VersionInfo{0, 1, 1, 0,} - err := CheckVersion(ledger.version, requiredVersion) - if err !=nil { - return err - } - - pathBytes, err := GetBip32bytes(bip32Path, 3) - if err != nil { - return err - } - - // Prepare message - header := []byte{userCLA, userINSPublicKeySECP256K1ShowBech32, 0, 0, 0} - message := append(header, byte(len(hrpBytes))) - message = append(message, hrpBytes...) - message = append(message, pathBytes...) - message[4] = byte(len(message) - len(header)) // update length - - _, err = ledger.api.Exchange(message) - - return err -} - -// ShowAddressSECP256K1 shows the address for the corresponding bip32 derivation path +// GetAddressPubKeySECP256K1 returns the pubkey (compressed) and address (bech( +// this command requires user confirmation in the device func (ledger *LedgerCosmos) GetAddressPubKeySECP256K1(bip32Path []uint32, hrp string) (pubkey []byte, addr string, err error) { // Check that app is at least 1.3.1 requiredVersion := VersionInfo{0, 1, 3, 1,} diff --git a/user_app_test.go b/user_app_test.go index 62b32f5..dd9b5d2 100644 --- a/user_app_test.go +++ b/user_app_test.go @@ -17,12 +17,12 @@ package ledger_cosmos_go import ( + "crypto/sha256" "encoding/hex" "fmt" - secp256k1 "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/crypto" "strings" "testing" ) @@ -54,7 +54,7 @@ func Test_UserGetVersion(t *testing.T) { assert.Equal(t, uint8(0x0), version.AppMode, "TESTING MODE ENABLED!!") assert.Equal(t, uint8(0x1), version.Major, "Wrong Major version") - assert.Equal(t, uint8(0x1), version.Minor, "Wrong Minor version") + assert.Equal(t, uint8(0x5), version.Minor, "Wrong Minor version") assert.Equal(t, uint8(0x0), version.Patch, "Wrong Patch version") } @@ -67,26 +67,20 @@ func Test_UserGetPublicKey(t *testing.T) { userApp.api.Logging = true - path := []uint32{44, 118, 0, 0, 0} + path := []uint32{44, 118, 5, 0, 21} pubKey, err := userApp.GetPublicKeySECP256K1(path) if err != nil { t.Fatalf("Detected error, err: %s\n", err.Error()) } - assert.Equal( - t, - 65, - len(pubKey), - "Public key has wrong length: %x, expected length: %x\n", pubKey, 65) - + assert.Equal(t, 33, len(pubKey), "Public key has wrong length: %x, expected length: %x\n", pubKey, 65) fmt.Printf("PUBLIC KEY: %x\n", pubKey) - _, err = secp256k1.ParsePubKey(pubKey[:], secp256k1.S256()) - require.Nil(t, err, "Error parsing public key err: %s\n", err) + assert.Equal(t, "03cb5a33c61595206294140c45efa8a817533e31aa05ea18343033a0732a677005", hex.EncodeToString(pubKey), "Unexpected pubkey") } -func Test_UserShowAddresses(t *testing.T) { +func Test_GetAddressPubKeySECP256K1_Zero(t *testing.T) { userApp, err := FindLedgerCosmosUserApp() if err != nil { t.Fatalf(err.Error()) @@ -98,10 +92,44 @@ func Test_UserShowAddresses(t *testing.T) { hrp := "cosmos" path := []uint32{44, 118, 0, 0, 0} - err = userApp.ShowAddressSECP256K1(path, hrp) + pubKey, addr, err := userApp.GetAddressPubKeySECP256K1(path, hrp) if err != nil { t.Fatalf("Detected error, err: %s\n", err.Error()) } + + fmt.Printf("PUBLIC KEY : %x\n", pubKey) + fmt.Printf("BECH32 ADDR: %s\n", addr) + + assert.Equal(t, 33, len(pubKey), "Public key has wrong length: %x, expected length: %x\n", pubKey, 65) + + assert.Equal(t, "034fef9cd7c4c63588d3b03feb5281b9d232cba34d6f3d71aee59211ffbfe1fe87", hex.EncodeToString(pubKey), "Unexpected pubkey") + assert.Equal(t, "cosmos1w34k53py5v5xyluazqpq65agyajavep2rflq6h", addr, "Unexpected addr") +} + +func Test_GetAddressPubKeySECP256K1(t *testing.T) { + userApp, err := FindLedgerCosmosUserApp() + if err != nil { + t.Fatalf(err.Error()) + } + defer userApp.Close() + + userApp.api.Logging = true + + hrp := "cosmos" + path := []uint32{44, 118, 5, 0, 21} + + pubKey, addr, err := userApp.GetAddressPubKeySECP256K1(path, hrp) + if err != nil { + t.Fatalf("Detected error, err: %s\n", err.Error()) + } + + fmt.Printf("PUBLIC KEY : %x\n", pubKey) + fmt.Printf("BECH32 ADDR: %s\n", addr) + + assert.Equal(t, 33, len(pubKey), "Public key has wrong length: %x, expected length: %x\n", pubKey, 65) + + assert.Equal(t, "03cb5a33c61595206294140c45efa8a817533e31aa05ea18343033a0732a677005", hex.EncodeToString(pubKey), "Unexpected pubkey") + assert.Equal(t, "cosmos162zm3k8mc685592d7vej2lxrp58mgmkcec76d6", addr, "Unexpected addr") } func Test_UserPK_HDPaths(t *testing.T) { @@ -116,16 +144,16 @@ func Test_UserPK_HDPaths(t *testing.T) { path := []uint32{44, 118, 0, 0, 0} expected := []string{ - "044fef9cd7c4c63588d3b03feb5281b9d232cba34d6f3d71aee59211ffbfe1fe877bff8521bf5243e80be922e51cee0faa8346b113fdec822c4d902e42b22bc345", - "0460d0487a3dfce9228eee2d0d83a40f6131f551526c8e52066fe7fe1e4a509666d60da24e97777510db9b238870e184891b580610ec6dafaf12c7abffed3670c6", - "04a2670393d02b162d0ed06a08041e80d86be36c0564335254df7462447eb69ab3f5a54ab07a8622ab23c28e9240ce58f4015ec401d95b08221b74e2a4a209ba6d", - "043222fc61795077791665544a90740e8ead638a391a3b8f9261f4a226b396c042a118bb64eccd89941d73de7cb12beed5a47de61049c7fc0d4708a4a0f5637957", - "04f577473348d7b01e7af2f245e36b98d181bc935ec8b552cde5932b646dc7be0415b9fd94af37dc295e25e35d3840fdd3cb1d0baa411bdc00d15dca427abdff3f", - "0422b1a5486be0a2d5f3c5866be46e05d1bde8cda5ea1c4c77a9bc48d2fa2753bcbb49b6c9d4be25bed7fb75c2e0c43c25175e88893c4f7963398a5aac3230c79e", - "0477a1c826d3a03ca4ee94fc4dea6bccb2bac5f2ac0419a128c29f8e88f1ff295ac6a16c770d38ee0e55bec83e8d8e3f1b1616ce77055a928255919340053a477d", - "041b75c84453935ab76f8c8d0b6566c3fcc101cc5c59d7000bfc9101961e9308d9228b0af378c4e6a38eeaf18175d2b2a7ab3fad9c9a4b117775f2e4a4ac633aff", - "048905a42433b1d677cc8afd36861430b9a8529171b0616f733659f131c3f80221e222d162dbcde7c77be3d82b4f666c2acc1e25aaeb3e4fadfb8c7c6b1282374b", - "048be7f348902d8c20bc88d32294f4f3b819284548122229decd1adf1a7eb0848bc4fbd7ac5bae3a854f2bcb0831c4550f48752f630a33a088d0fd166d8d3435d9", + "034fef9cd7c4c63588d3b03feb5281b9d232cba34d6f3d71aee59211ffbfe1fe87", + "0260d0487a3dfce9228eee2d0d83a40f6131f551526c8e52066fe7fe1e4a509666", + "03a2670393d02b162d0ed06a08041e80d86be36c0564335254df7462447eb69ab3", + "033222fc61795077791665544a90740e8ead638a391a3b8f9261f4a226b396c042", + "03f577473348d7b01e7af2f245e36b98d181bc935ec8b552cde5932b646dc7be04", + "0222b1a5486be0a2d5f3c5866be46e05d1bde8cda5ea1c4c77a9bc48d2fa2753bc", + "0377a1c826d3a03ca4ee94fc4dea6bccb2bac5f2ac0419a128c29f8e88f1ff295a", + "031b75c84453935ab76f8c8d0b6566c3fcc101cc5c59d7000bfc9101961e9308d9", + "038905a42433b1d677cc8afd36861430b9a8529171b0616f733659f131c3f80221", + "038be7f348902d8c20bc88d32294f4f3b819284548122229decd1adf1a7eb0848b", } for i := uint32(0); i < 10; i++ { @@ -138,7 +166,7 @@ func Test_UserPK_HDPaths(t *testing.T) { assert.Equal( t, - 65, + 33, len(pubKey), "Public key has wrong length: %x, expected length: %x\n", pubKey, 65) @@ -148,7 +176,7 @@ func Test_UserPK_HDPaths(t *testing.T) { hex.EncodeToString(pubKey), "Public key 44'/118'/0'/0/%d does not match\n", i) - _, err = secp256k1.ParsePubKey(pubKey[:], secp256k1.S256()) + _, err = btcec.ParsePubKey(pubKey[:], btcec.S256()) require.Nil(t, err, "Error parsing public key err: %s\n", err) } @@ -201,19 +229,20 @@ func Test_UserSign(t *testing.T) { return } - pub2, err := secp256k1.ParsePubKey(pubKey[:], secp256k1.S256()) + pub2, err := btcec.ParsePubKey(pubKey[:], btcec.S256()) if err != nil { t.Fatalf("[ParsePK] Error: " + err.Error()) return } - sig2, err := secp256k1.ParseDERSignature(signature[:], secp256k1.S256()) + sig2, err := btcec.ParseDERSignature(signature[:], btcec.S256()) if err != nil { t.Fatalf("[ParseSig] Error: " + err.Error()) return } - verified := sig2.Verify(crypto.Sha256(message), pub2) + hash := sha256.Sum256(message) + verified := sig2.Verify(hash[:], pub2) if !verified { t.Fatalf("[VerifySig] Error verifying signature: " + err.Error()) return @@ -236,5 +265,5 @@ func Test_UserSign_Fails(t *testing.T) { message = append(garbage, message...) _, err = userApp.SignSECP256K1(path, message) - assert.EqualError(t, err, "Unexpected character in JSON string") + assert.EqualError(t, err, "Invalid character in JSON string") } diff --git a/validator_app_test.go b/validator_app_test.go index 6b95591..08340ac 100644 --- a/validator_app_test.go +++ b/validator_app_test.go @@ -33,9 +33,9 @@ func Test_ValGetVersion(t *testing.T) { version, err := validatorApp.GetVersion() require.Nil(t, err, "Detected error") - assert.Equal(t, uint8(0xFF), version.AppMode, "TESTING MODE NOT ENABLED") + assert.Equal(t, uint8(0x0), version.AppMode, "TESTING MODE NOT ENABLED") assert.Equal(t, uint8(0x0), version.Major, "Wrong Major version") - assert.Equal(t, uint8(0x5), version.Minor, "Wrong Minor version") + assert.Equal(t, uint8(0x9), version.Minor, "Wrong Minor version") assert.Equal(t, uint8(0x0), version.Patch, "Wrong Patch version") }