Skip to content

Commit

Permalink
fix(wallet/ledger): Add support for sr25519-derived addresses
Browse files Browse the repository at this point in the history
  • Loading branch information
matevz committed Sep 26, 2023
1 parent b924ef8 commit 00654d4
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 21 deletions.
53 changes: 34 additions & 19 deletions wallet/ledger/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ import (
"golang.org/x/crypto/sha3"

"github.com/oasisprotocol/oasis-core/go/common/cbor"
coreSignature "github.com/oasisprotocol/oasis-core/go/common/crypto/signature"
staking "github.com/oasisprotocol/oasis-core/go/staking/api"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/crypto/signature"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/crypto/signature/ed25519"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/crypto/signature/sr25519"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/types"

"github.com/oasisprotocol/cli/wallet"
)

// NOTE: Some of this is lifted from https://github.com/oasisprotocol/oasis-core-ledger but updated
Expand Down Expand Up @@ -75,24 +78,24 @@ func (ld *ledgerDevice) GetVersion() (*VersionInfo, error) {
}, nil
}

// GetPublicKeyEd25519 returns the Ed25519 public key associated with the given derivation path.
// If the requireConfirmation flag is set, this will require confirmation from the user.
func (ld *ledgerDevice) GetPublicKeyEd25519(path []uint32, requireConfirmation bool) ([]byte, error) {
return ld.getPublicKey25519(path, insGetAddrEd25519, requireConfirmation)
}

// GetPublicKeySr25519 returns the Sr25519 public key associated with the given derivation path.
// GetPublicKey25519 returns the Ed25519 or Sr25519 public key associated with the given derivation path.
// If the requireConfirmation flag is set, this will require confirmation from the user.
func (ld *ledgerDevice) GetPublicKeySr25519(path []uint32, requireConfirmation bool) ([]byte, error) {
return ld.getPublicKey25519(path, insGetAddrSr25519, requireConfirmation)
}

func (ld *ledgerDevice) getPublicKey25519(path []uint32, ins byte, requireConfirmation bool) ([]byte, error) {
func (ld *ledgerDevice) GetPublicKey25519(path []uint32, algorithm string, requireConfirmation bool) ([]byte, error) {
pathBytes, err := getSerializedPath(path)
if err != nil {
return nil, fmt.Errorf("ledger: failed to get serialized path bytes: %w", err)
}

var ins byte
switch algorithm {
case wallet.AlgorithmEd25519Adr8:
ins = insGetAddrEd25519
case wallet.AlgorithmSr25519Adr8:
ins = insGetAddrSr25519
default:
return nil, fmt.Errorf("ledger: unknown provided algorithm %s", algorithm)
}

response, err := ld.getPublicKeyRaw(pathBytes, ins, requireConfirmation)
if err != nil {
return nil, err
Expand All @@ -105,16 +108,28 @@ func (ld *ledgerDevice) getPublicKey25519(path []uint32, ins byte, requireConfir
rawPubkey := response[0:32]
rawAddr := string(response[32:])

var pubkey coreSignature.PublicKey
if err = pubkey.UnmarshalBinary(rawPubkey); err != nil {
return nil, fmt.Errorf("ledger: device returned malformed public key: %w", err)
// Sanity check, if the public key matches the expected address shown on Ledger.
var addrSpec types.SignatureAddressSpec
switch algorithm {
case wallet.AlgorithmEd25519Adr8:
addrSpec.Ed25519 = &ed25519.PublicKey{}
if err = addrSpec.Ed25519.UnmarshalBinary(rawPubkey); err != nil {
return nil, fmt.Errorf("ledger: device returned malformed public key: %w", err)
}
case wallet.AlgorithmSr25519Adr8:
addrSpec.Sr25519 = &sr25519.PublicKey{}
if err = addrSpec.Sr25519.UnmarshalBinary(rawPubkey); err != nil {
return nil, fmt.Errorf("ledger: device returned malformed public key: %w", err)
}
default:
return nil, fmt.Errorf("ledger: unknown provided algorithm %s", algorithm)
}

var addrFromDevice staking.Address
var addrFromDevice types.Address
if err = addrFromDevice.UnmarshalText([]byte(rawAddr)); err != nil {
return nil, fmt.Errorf("ledger: device returned malformed account address: %w", err)
}
addrFromPubkey := staking.NewAddress(pubkey)
addrFromPubkey := types.NewAddress(addrSpec)
if !addrFromDevice.Equal(addrFromPubkey) {
return nil, fmt.Errorf(
"ledger: account address computed on device (%s) doesn't match internally computed account address (%s)",
Expand Down
4 changes: 2 additions & 2 deletions wallet/ledger/ledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ func newAccount(cfg *accountConfig) (wallet.Account, error) {
if cfg.Algorithm == wallet.AlgorithmEd25519Legacy {
path = getLegacyPath(cfg.Number)
}
rawPk, err := dev.GetPublicKeyEd25519(path, false)
rawPk, err := dev.GetPublicKey25519(path, wallet.AlgorithmEd25519Adr8, false)
if err != nil {
_ = dev.Close()
return nil, err
Expand Down Expand Up @@ -219,7 +219,7 @@ func newAccount(cfg *accountConfig) (wallet.Account, error) {
pk = secp256k1pk
case wallet.AlgorithmSr25519Adr8:
path = getAdr0008Path(cfg.Number)
rawPk, err := dev.GetPublicKeySr25519(path, false)
rawPk, err := dev.GetPublicKey25519(path, wallet.AlgorithmSr25519Adr8, false)
if err != nil {
_ = dev.Close()
return nil, err
Expand Down

0 comments on commit 00654d4

Please sign in to comment.