diff --git a/derivationpath/encoder.go b/derivationpath/encoder.go new file mode 100644 index 0000000..c1f5b02 --- /dev/null +++ b/derivationpath/encoder.go @@ -0,0 +1,36 @@ +package derivationpath + +import ( + "bytes" + "encoding/binary" + "fmt" + "strings" +) + +func Encode(rawPath []uint32) string { + segments := []string{string(tokenMaster)} + + for _, i := range rawPath { + suffix := "" + + if i >= hardenedStart { + i = i - hardenedStart + suffix = string(tokenHardened) + } + + segments = append(segments, fmt.Sprintf("%d%s", i, suffix)) + } + + return strings.Join(segments, string(tokenSeparator)) +} + +func EncodeFromBytes(data []byte) (string, error) { + buf := bytes.NewBuffer(data) + rawPath := make([]uint32, buf.Len()/4) + err := binary.Read(buf, binary.BigEndian, &rawPath) + if err != nil { + return "", err + } + + return Encode(rawPath), nil +} diff --git a/derivationpath/encoder_test.go b/derivationpath/encoder_test.go new file mode 100644 index 0000000..7acaf50 --- /dev/null +++ b/derivationpath/encoder_test.go @@ -0,0 +1,35 @@ +package derivationpath + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestEncode(t *testing.T) { + scenarios := []struct { + path []uint32 + expectedPath string + }{ + { + path: []uint32{}, + expectedPath: "m", + }, + { + path: []uint32{0, 1, 2}, + expectedPath: "m/0/1/2", + }, + { + path: []uint32{hardenedStart + 10, 1, 2}, + expectedPath: "m/10'/1/2", + }, + } + + for i, s := range scenarios { + t.Run(fmt.Sprintf("scenario %d", i), func(t *testing.T) { + path := Encode(s.path) + assert.Equal(t, s.expectedPath, path) + }) + } +} diff --git a/types/application_status.go b/types/application_status.go index 47c3040..12eece3 100644 --- a/types/application_status.go +++ b/types/application_status.go @@ -2,12 +2,10 @@ package types import ( "bytes" - "encoding/binary" "errors" - "fmt" - "strings" "github.com/status-im/keycard-go/apdu" + "github.com/status-im/keycard-go/derivationpath" ) const hardenedStart = 0x80000000 // 2^31 @@ -48,24 +46,13 @@ func ParseApplicationStatus(data []byte) (*ApplicationStatus, error) { func parseKeyPathStatus(data []byte) (*ApplicationStatus, error) { appStatus := &ApplicationStatus{} - buf := bytes.NewBuffer(data) - rawPath := make([]uint32, buf.Len()/4) - err := binary.Read(buf, binary.BigEndian, &rawPath) + + path, err := derivationpath.EncodeFromBytes(data) if err != nil { return nil, err } - segments := []string{"m"} - for _, i := range rawPath { - suffix := "" - if i >= hardenedStart { - i = i - hardenedStart - suffix = "'" - } - segments = append(segments, fmt.Sprintf("%d%s", i, suffix)) - } - - appStatus.Path = strings.Join(segments, "/") + appStatus.Path = path return appStatus, nil }