Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions cosmos/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ func Test_PathGeneration0(t *testing.T) {
bip32Path := []uint32{44, 100, 0, 0, 0}

pathBytes, err := GetBip32bytesv1(bip32Path, 0)

if err != nil {
t.Fatalf("Detected error, err: %s\n", err.Error())
}
Expand All @@ -57,7 +56,6 @@ func Test_PathGeneration2(t *testing.T) {
bip32Path := []uint32{44, 118, 0, 0, 0}

pathBytes, err := GetBip32bytesv1(bip32Path, 2)

if err != nil {
t.Fatalf("Detected error, err: %s\n", err.Error())
}
Expand All @@ -81,7 +79,6 @@ func Test_PathGeneration3(t *testing.T) {
bip32Path := []uint32{44, 118, 0, 0, 0}

pathBytes, err := GetBip32bytesv1(bip32Path, 3)

if err != nil {
t.Fatalf("Detected error, err: %s\n", err.Error())
}
Expand All @@ -105,7 +102,6 @@ func Test_PathGeneration0v2(t *testing.T) {
bip32Path := []uint32{44, 100, 0, 0, 0}

pathBytes, err := GetBip32bytesv2(bip32Path, 0)

if err != nil {
t.Fatalf("Detected error, err: %s\n", err.Error())
}
Expand All @@ -129,7 +125,6 @@ func Test_PathGeneration2v2(t *testing.T) {
bip32Path := []uint32{44, 118, 0, 0, 0}

pathBytes, err := GetBip32bytesv2(bip32Path, 2)

if err != nil {
t.Fatalf("Detected error, err: %s\n", err.Error())
}
Expand All @@ -153,7 +148,6 @@ func Test_PathGeneration3v2(t *testing.T) {
bip32Path := []uint32{44, 118, 0, 0, 0}

pathBytes, err := GetBip32bytesv2(bip32Path, 3)

if err != nil {
t.Fatalf("Detected error, err: %s\n", err.Error())
}
Expand Down
2 changes: 1 addition & 1 deletion cosmos/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
)

replace (
github.com/zondax/hid => github.com/troian/hid v0.13.2
github.com/zondax/hid => github.com/troian/hid v0.14.0
github.com/zondax/ledger-go => ../
)

Expand Down
5 changes: 3 additions & 2 deletions cosmos/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/troian/hid v0.13.2 h1:O7PWZQm5YGyg0nVvknFVLVrNTPillz4ZXvxJOtoyteE=
github.com/troian/hid v0.13.2/go.mod h1:n6adloQ1876oEXZr6fFsthy4FDHxwJhh7QYQspm30Ds=
github.com/troian/hid v0.14.0 h1:yp6jM7YT62r7cDf3Tbjq5i1vmiSdG5RS8rJ5rc/URpM=
github.com/troian/hid v0.14.0/go.mod h1:WDhBi5aR0Z3CR19aSCgl6yJ1+My/G8753VPBu3caQp4=
github.com/zondax/golem v0.27.0 h1:IbBjGIXF3SoGOZHsILJvIM/F/ylwJzMcHAcggiqniPw=
github.com/zondax/golem v0.27.0/go.mod h1:AmorCgJPt00L8xN1VrMBe13PSifoZksnQ1Ge906bu4A=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
Expand All @@ -48,6 +48,7 @@ go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
Expand Down
150 changes: 52 additions & 98 deletions cosmos/user_app.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ package ledger_cosmos_go

import (
"errors"
"fmt"
"math"

"github.com/zondax/ledger-go"
)
Expand All @@ -30,8 +28,6 @@ const (
userINSGetVersion = 0
userINSSignSECP256K1 = 2
userINSGetAddrSecp256k1 = 4

userMessageChunkSize = 250
)

var (
Expand Down Expand Up @@ -185,93 +181,79 @@ func (ledger *LedgerCosmos) GetBip32bytes(bip32Path []uint32, _ int) ([]byte, er
return pathBytes, nil
}

// cosmosErrorHandler provides custom error handling for Cosmos app
func cosmosErrorHandler(err error, response []byte, instruction byte) error {
if err.Error() == "[APDU_CODE_BAD_KEY_HANDLE] The parameters in the data field are incorrect" {
// In this special case, we can extract additional info
errorMsg := string(response)
switch errorMsg {
case "ERROR: JSMN_ERROR_NOMEM":
return errors.New("Not enough tokens were provided")
case "PARSER ERROR: JSMN_ERROR_INVAL":
return errors.New("Unexpected character in JSON string")
case "PARSER ERROR: JSMN_ERROR_PART":
return errors.New("The JSON string is not a complete.")
}
return errors.New(errorMsg)
}
if err.Error() == "[APDU_CODE_DATA_INVALID] Referenced data reversibly blocked (invalidated)" {
errorMsg := string(response)
return errors.New(errorMsg)
}
return err
}

func (ledger *LedgerCosmos) signv1(bip32Path []uint32, transaction []byte) ([]byte, error) {
var packetIndex byte = 1
packetCount := 1 + byte(math.Ceil(float64(len(transaction))/float64(userMessageChunkSize)))
// Get path bytes
pathBytes, err := ledger.GetBip32bytes(bip32Path, 3)
if err != nil {
return nil, err
}

// Prepare chunks using ledger-go chunking
chunks := ledger_go.PrepareChunks(pathBytes, transaction)

// For v1, we need to handle the packet indexing differently
// v1 uses 1-based packet indexing in P1 and packet count in P2
packetCount := byte(len(chunks))
var finalResponse []byte
var message []byte

for packetIndex <= packetCount {
chunk := userMessageChunkSize
if packetIndex == 1 {
pathBytes, err := ledger.GetBip32bytes(bip32Path, 3)
if err != nil {
return nil, err
}
header := []byte{userCLA, userINSSignSECP256K1, packetIndex, packetCount, byte(len(pathBytes))}
message = append(header, pathBytes...)
} else {
if len(transaction) < userMessageChunkSize {
chunk = len(transaction)
}
header := []byte{userCLA, userINSSignSECP256K1, packetIndex, packetCount, byte(chunk)}
message = append(header, transaction[:chunk]...)
}

for packetIndex, chunk := range chunks {
// v1 uses 1-based indexing
p1 := byte(packetIndex + 1)
p2 := packetCount
payloadLen := byte(len(chunk))

header := []byte{userCLA, userINSSignSECP256K1, p1, p2, payloadLen}
message := append(header, chunk...)

response, err := ledger.api.Exchange(message)
if err != nil {
return nil, processErrorResponse(response, err)
return nil, cosmosErrorHandler(err, response, userINSSignSECP256K1)
}

finalResponse = response
if packetIndex > 1 {
transaction = transaction[chunk:]
}
packetIndex++
}

return finalResponse, nil
}

func (ledger *LedgerCosmos) signv2(bip32Path []uint32, transaction []byte, p2 byte) ([]byte, error) {
var packetIndex byte = 1
packetCount := 1 + byte(math.Ceil(float64(len(transaction))/float64(userMessageChunkSize)))

var finalResponse []byte

var message []byte

if p2 > 1 {
return nil, errors.New("only values of SIGN_MODE_LEGACY_AMINO (P2=0) and SIGN_MODE_TEXTUAL (P2=1) are allowed")
}

for packetIndex <= packetCount {
chunk := userMessageChunkSize
if packetIndex == 1 {
pathBytes, err := ledger.GetBip32bytes(bip32Path, 3)
if err != nil {
return nil, err
}
header := []byte{userCLA, userINSSignSECP256K1, 0, p2, byte(len(pathBytes))}
message = append(header, pathBytes...)
} else {
if len(transaction) < userMessageChunkSize {
chunk = len(transaction)
}

payloadDesc := byte(1)
if packetIndex == packetCount {
payloadDesc = byte(2)
}

header := []byte{userCLA, userINSSignSECP256K1, payloadDesc, p2, byte(chunk)}
message = append(header, transaction[:chunk]...)
}

response, err := ledger.api.Exchange(message)
if err != nil {
return nil, processErrorResponse(response, err)
}
// Get path bytes
pathBytes, err := ledger.GetBip32bytes(bip32Path, 3)
if err != nil {
return nil, err
}

finalResponse = response
if packetIndex > 1 {
transaction = transaction[chunk:]
}
packetIndex++
// Prepare chunks using ledger-go chunking
chunks := ledger_go.PrepareChunks(pathBytes, transaction)

}
return finalResponse, nil
// Use ProcessChunks with custom error handler
return ledger_go.ProcessChunks(ledger.api, chunks, userCLA, userINSSignSECP256K1, p2, cosmosErrorHandler)
}

// GetAddressPubKeySECP256K1 returns the pubkey (compressed) and address (bech(
Expand Down Expand Up @@ -320,31 +302,3 @@ func (ledger *LedgerCosmos) getAddressPubKeySECP256K1(bip32Path []uint32, hrp st

return pubkey, addr, err
}

func processErrorResponse(response []byte, err error) error {
// In this special case, we can extract additional info
msg := string(response)

if msg == "" {
msg = err.Error()
}

switch err.Error() {
case errLedgerApduBadKeyHandle:
// In this special case, we can extract additional info
switch msg {
case "ERROR: JSMN_ERROR_NOMEM":
err = errNotEnoughTokens
case "PARSER ERROR: JSMN_ERROR_INVAL":
err = errUnexpectedJsonCharacter
case "PARSER ERROR: JSMN_ERROR_PART":
err = errIncompleteJsonString
default:
err = fmt.Errorf("ledger-cosmos: unknown error - %s", msg)
}
case errLedgerApduDataInvalid:
err = fmt.Errorf("ledger-cosmos: unknown error - %s", msg)
}

return err
}
Loading