Skip to content

Commit

Permalink
new comm package
Browse files Browse the repository at this point in the history
  • Loading branch information
ftheirs committed Dec 20, 2023
1 parent 1efb301 commit e73dd82
Show file tree
Hide file tree
Showing 4 changed files with 577 additions and 134 deletions.
120 changes: 57 additions & 63 deletions common.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* (c) 2018 - 2022 ZondaX AG
* (c) 2018 - 2023 ZondaX AG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -18,89 +18,83 @@ package ledger_cosmos_go

import (
"encoding/binary"
"errors"
"fmt"
"strconv"
"strings"
)

// VersionInfo contains app version information
type VersionInfo struct {
AppMode uint8
Major uint8
Minor uint8
Patch uint8
type VersionResponse struct {
AppMode uint8 // 0: release | 0xFF: debug
Major uint8
Minor uint8
Patch uint8
AppLocked uint8
TargetId uint32
}

func (c VersionInfo) String() string {
return fmt.Sprintf("%d.%d.%d", c.Major, c.Minor, c.Patch)
}

// VersionRequiredError the command is not supported by this app
type VersionRequiredError struct {
Found VersionInfo
Required VersionInfo
type AddressResponse struct {
pubkey []byte // 0: release | 0xFF: debug
address string
}

func (e VersionRequiredError) Error() string {
return fmt.Sprintf("App Version required %s - Version found: %s", e.Required, e.Found)
type SignatureResponse struct {
signatureDER []byte
}

func NewVersionRequiredError(req VersionInfo, ver VersionInfo) error {
return &VersionRequiredError{
Found: ver,
Required: req,
}
func (c VersionResponse) String() string {
return fmt.Sprintf("%d.%d.%d", c.Major, c.Minor, c.Patch)
}

// CheckVersion compares the current version with the required version
func CheckVersion(ver VersionInfo, req VersionInfo) error {
if ver.Major != req.Major {
if ver.Major > req.Major {
return nil
}
return NewVersionRequiredError(req, ver)
// Validate HRP: Max length = 83
// All characters must be in range [33, 126], displayable chars in Ledger devices
func serializeHRP(hrp string) (hrpBytes []byte, err error) {
if len(hrp) > 83 {
return nil, errors.New("HRP len should be <= 83")
}

if ver.Minor != req.Minor {
if ver.Minor > req.Minor {
return nil
hrpBytes = []byte(hrp)
for _, b := range hrpBytes {
if b < 33 || b > 126 {
return nil, errors.New("all characters in the HRP must be in the [33, 126] range")
}
return NewVersionRequiredError(req, ver)
}

if ver.Patch >= req.Patch {
return nil
}
return NewVersionRequiredError(req, ver)
return hrpBytes, nil
}

func GetBip32bytesv1(bip32Path []uint32, hardenCount int) ([]byte, error) {
message := make([]byte, 41)
if len(bip32Path) > 10 {
return nil, fmt.Errorf("maximum bip32 depth = 10")
}
message[0] = byte(len(bip32Path))
for index, element := range bip32Path {
pos := 1 + index*4
value := element
if index < hardenCount {
value = 0x80000000 | element
}
binary.LittleEndian.PutUint32(message[pos:], value)
func serializePath(path string) (pathBytes []byte, err error) {
const HARDENED = 0x80000000

if !strings.HasPrefix(path, "m/") {
return nil, errors.New(`path should start with "m/" (e.g "m/44'/118'/0'/0/3")`)
}
return message, nil
}

func GetBip32bytesv2(bip44Path []uint32, hardenCount int) ([]byte, error) {
message := make([]byte, 20)
if len(bip44Path) != 5 {
return nil, fmt.Errorf("path should contain 5 elements")
pathArray := strings.Split(path, "/")
pathArray = pathArray[1:] // remove "m"

if len(pathArray) != 5 {
return nil, errors.New("invalid path: it must contain 5 elements")
}
for index, element := range bip44Path {
pos := index * 4
value := element
if index < hardenCount {
value = 0x80000000 | element

// Reserve 20 bytes for serialized path
buffer := make([]byte, 4*len(pathArray))

for i, child := range pathArray {
value := 0
if strings.HasSuffix(child, "'") {
value += HARDENED
child = strings.TrimSuffix(child, "'")
}
numChild, err := strconv.Atoi(child)
if err != nil {
return nil, fmt.Errorf("invalid path : %s is not a number (e.g \"m/44'/118'/0'/0/3\")", child)
}
if numChild >= HARDENED {
return nil, errors.New("incorrect child value (bigger or equal to 0x80000000)")
}
binary.LittleEndian.PutUint32(message[pos:], value)
value += numChild
binary.LittleEndian.PutUint32(buffer[i*4:], uint32(value))
}
return message, nil
return buffer, nil
}
113 changes: 42 additions & 71 deletions common_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* (c) 2018 - 2022 Zondax AG
* (c) 2018 - 2023 Zondax AG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -18,20 +18,20 @@ package ledger_cosmos_go

import (
"fmt"
"github.com/stretchr/testify/assert"
"testing"

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

func Test_PrintVersion(t *testing.T) {
reqVersion := VersionInfo{0, 1, 2, 3}
reqVersion := VersionResponse{0, 1, 2, 3, 0, 0x12345678}
s := fmt.Sprintf("%v", reqVersion)
assert.Equal(t, "1.2.3", s)
}

func Test_PathGeneration0(t *testing.T) {
bip32Path := []uint32{44, 100, 0, 0, 0}

pathBytes, err := GetBip32bytesv1(bip32Path, 0)
func Test_SerializePath0(t *testing.T) {
path := "m/44'/100'/0/0/0"
pathBytes, err := serializePath(path)

if err != nil {
t.Fatalf("Detected error, err: %s\n", err.Error())
Expand All @@ -41,21 +41,19 @@ func Test_PathGeneration0(t *testing.T) {

assert.Equal(
t,
41,
20,
len(pathBytes),
"PathBytes has wrong length: %x, expected length: %x\n", pathBytes, 41)
"PathBytes has wrong length: %x, expected length: %x\n", pathBytes, 20)

assert.Equal(
t,
"052c000000640000000000000000000000000000000000000000000000000000000000000000000000",
"2c00008064000080000000000000000000000000",
fmt.Sprintf("%x", pathBytes),
"Unexpected PathBytes\n")
}

func Test_PathGeneration2(t *testing.T) {
bip32Path := []uint32{44, 118, 0, 0, 0}

pathBytes, err := GetBip32bytesv1(bip32Path, 2)
func Test_SerializePath1(t *testing.T) {
path := "m/44'/118'/0'/0/0"
pathBytes, err := serializePath(path)

if err != nil {
t.Fatalf("Detected error, err: %s\n", err.Error())
Expand All @@ -65,21 +63,20 @@ func Test_PathGeneration2(t *testing.T) {

assert.Equal(
t,
41,
20,
len(pathBytes),
"PathBytes has wrong length: %x, expected length: %x\n", pathBytes, 41)
"PathBytes has wrong length: %x, expected length: %x\n", pathBytes, 20)

assert.Equal(
t,
"052c000080760000800000000000000000000000000000000000000000000000000000000000000000",
"2c00008076000080000000800000000000000000",
fmt.Sprintf("%x", pathBytes),
"Unexpected PathBytes\n")
}

func Test_PathGeneration3(t *testing.T) {
bip32Path := []uint32{44, 118, 0, 0, 0}

pathBytes, err := GetBip32bytesv1(bip32Path, 3)
func Test_SerializePath2(t *testing.T) {
path := "m/44'/60'/0'/0/0"
pathBytes, err := serializePath(path)

if err != nil {
t.Fatalf("Detected error, err: %s\n", err.Error())
Expand All @@ -89,85 +86,59 @@ func Test_PathGeneration3(t *testing.T) {

assert.Equal(
t,
41,
20,
len(pathBytes),
"PathBytes has wrong length: %x, expected length: %x\n", pathBytes, 41)
"PathBytes has wrong length: %x, expected length: %x\n", pathBytes, 20)

assert.Equal(
t,
"052c000080760000800000008000000000000000000000000000000000000000000000000000000000",
"2c0000803c000080000000800000000000000000",
fmt.Sprintf("%x", pathBytes),
"Unexpected PathBytes\n")
}

func Test_PathGeneration0v2(t *testing.T) {
bip32Path := []uint32{44, 100, 0, 0, 0}

pathBytes, err := GetBip32bytesv2(bip32Path, 0)
func Test_SerializeHRP0(t *testing.T) {
hrp := "cosmos"
hrpBytes, err := serializeHRP(hrp)

if err != nil {
t.Fatalf("Detected error, err: %s\n", err.Error())
}

fmt.Printf("Path: %x\n", pathBytes)
fmt.Printf("HRP: %x\n", hrpBytes)

assert.Equal(
t,
40,
len(pathBytes),
"PathBytes has wrong length: %x, expected length: %x\n", pathBytes, 40)
6,
len(hrpBytes),
"hrpBytes has wrong length: %x, expected length: %x\n", hrpBytes, 6)

assert.Equal(
t,
"2c000000640000000000000000000000000000000000000000000000000000000000000000000000",
fmt.Sprintf("%x", pathBytes),
"Unexpected PathBytes\n")
"636f736d6f73",
fmt.Sprintf("%x", hrpBytes),
"Unexpected HRPBytes\n")
}

func Test_PathGeneration2v2(t *testing.T) {
bip32Path := []uint32{44, 118, 0, 0, 0}

pathBytes, err := GetBip32bytesv2(bip32Path, 2)
func Test_SerializeHRP1(t *testing.T) {
hrp := "evmos"
hrpBytes, err := serializeHRP(hrp)

if err != nil {
t.Fatalf("Detected error, err: %s\n", err.Error())
}

fmt.Printf("Path: %x\n", pathBytes)
fmt.Printf("HRP: %x\n", hrpBytes)

assert.Equal(
t,
40,
len(pathBytes),
"PathBytes has wrong length: %x, expected length: %x\n", pathBytes, 40)
5,
len(hrpBytes),
"hrpBytes has wrong length: %x, expected length: %x\n", hrpBytes, 5)

assert.Equal(
t,
"2c000080760000800000000000000000000000000000000000000000000000000000000000000000",
fmt.Sprintf("%x", pathBytes),
"Unexpected PathBytes\n")
}

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())
}

fmt.Printf("Path: %x\n", pathBytes)

assert.Equal(
t,
40,
len(pathBytes),
"PathBytes has wrong length: %x, expected length: %x\n", pathBytes, 40)

assert.Equal(
t,
"2c000080760000800000008000000000000000000000000000000000000000000000000000000000",
fmt.Sprintf("%x", pathBytes),
"Unexpected PathBytes\n")
"65766d6f73",
fmt.Sprintf("%x", hrpBytes),
"Unexpected HRPBytes\n")
}
Loading

0 comments on commit e73dd82

Please sign in to comment.