Skip to content

Commit

Permalink
Merge pull request #109 from oasisprotocol/matevz/feature/sr25519-ledger
Browse files Browse the repository at this point in the history
Sr25519 support for Ledger
  • Loading branch information
matevz authored Aug 10, 2023
2 parents 5c27e5d + faeb4ab commit a3260c7
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 11 deletions.
36 changes: 31 additions & 5 deletions wallet/file/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ import (
"github.com/oasisprotocol/deoxysii"
"github.com/oasisprotocol/oasis-core/go/common/crypto/sakg"
coreSignature "github.com/oasisprotocol/oasis-core/go/common/crypto/signature"

"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/secp256k1"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/crypto/signature/sr25519"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/types"

"github.com/oasisprotocol/cli/config"
Expand All @@ -45,14 +45,14 @@ const (
// SupportedAlgorithmsForImport returns the algorithms supported by the given import kind.
func SupportedAlgorithmsForImport(kind *wallet.ImportKind) []string {
if kind == nil {
return []string{wallet.AlgorithmEd25519Adr8, wallet.AlgorithmEd25519Raw, wallet.AlgorithmSecp256k1Bip44, wallet.AlgorithmSecp256k1Raw}
return []string{wallet.AlgorithmEd25519Adr8, wallet.AlgorithmEd25519Raw, wallet.AlgorithmSecp256k1Bip44, wallet.AlgorithmSecp256k1Raw, wallet.AlgorithmSr25519Raw}
}

switch *kind {
case wallet.ImportKindMnemonic:
return []string{wallet.AlgorithmEd25519Adr8, wallet.AlgorithmSecp256k1Bip44}
case wallet.ImportKindPrivateKey:
return []string{wallet.AlgorithmEd25519Raw, wallet.AlgorithmSecp256k1Raw}
return []string{wallet.AlgorithmEd25519Raw, wallet.AlgorithmSecp256k1Raw, wallet.AlgorithmSr25519Raw}
default:
return []string{}
}
Expand Down Expand Up @@ -258,6 +258,8 @@ func (af *fileAccountFactory) DataPrompt(kind wallet.ImportKind, rawCfg map[stri
return &survey.Multiline{Message: "Private key (base64-encoded):"}
case wallet.AlgorithmSecp256k1Raw:
return &survey.Multiline{Message: "Private key (hex-encoded):"}
case wallet.AlgorithmSr25519Raw:
return &survey.Multiline{Message: "Private key (base64-encoded):"}
default:
return nil
}
Expand Down Expand Up @@ -288,6 +290,12 @@ func (af *fileAccountFactory) DataValidator(kind wallet.ImportKind, rawCfg map[s
if err != nil {
return fmt.Errorf("private key must be hex-encoded (without leading 0x): %w", err)
}
case wallet.AlgorithmSr25519Raw:
// Ensure the private key is base64 encoded.
_, err := base64.StdEncoding.DecodeString(ans.(string))
if err != nil {
return fmt.Errorf("private key must be base64-encoded: %w", err)
}
default:
return fmt.Errorf("unsupported algorithm for %s: %s", wallet.ImportKindPrivateKey, cfg.Algorithm)
}
Expand Down Expand Up @@ -427,7 +435,7 @@ func (af *fileAccountFactory) Import(name string, passphrase string, rawCfg map[
}
case wallet.ImportKindPrivateKey:
switch cfg.Algorithm {
case wallet.AlgorithmEd25519Raw, wallet.AlgorithmSecp256k1Raw:
case wallet.AlgorithmEd25519Raw, wallet.AlgorithmSecp256k1Raw, wallet.AlgorithmSr25519Raw:
default:
return nil, fmt.Errorf("algorithm '%s' does not support import from private key", cfg.Algorithm)
}
Expand Down Expand Up @@ -512,6 +520,22 @@ func newAccount(state *secretState, cfg *accountConfig) (wallet.Account, error)
return nil, fmt.Errorf("failed to initialize signer: %w", err)
}

return &fileAccount{
cfg: cfg,
state: state,
signer: signer,
}, nil
case wallet.AlgorithmSr25519Raw:
// For Sr25519-Raw use the raw private key.
dataRaw, err := base64.StdEncoding.DecodeString(state.Data)
if err != nil {
return nil, err
}
signer, err := sr25519.NewSigner(dataRaw)
if err != nil {
return nil, err
}

return &fileAccount{
cfg: cfg,
state: state,
Expand Down Expand Up @@ -561,6 +585,8 @@ func (a *fileAccount) SignatureAddressSpec() types.SignatureAddressSpec {
return types.NewSignatureAddressSpecEd25519(a.Signer().Public().(ed25519.PublicKey))
case wallet.AlgorithmSecp256k1Bip44, wallet.AlgorithmSecp256k1Raw:
return types.NewSignatureAddressSpecSecp256k1Eth(a.Signer().Public().(secp256k1.PublicKey))
case wallet.AlgorithmSr25519Adr8, wallet.AlgorithmSr25519Raw:
return types.NewSignatureAddressSpecSr25519(a.Signer().Public().(sr25519.PublicKey))
default:
return types.SignatureAddressSpec{}
}
Expand All @@ -572,7 +598,7 @@ func (a *fileAccount) UnsafeExport() string {

func init() {
flags := flag.NewFlagSet("", flag.ContinueOnError)
flags.String(cfgAlgorithm, wallet.AlgorithmEd25519Adr8, fmt.Sprintf("Cryptographic algorithm to use for this account [%s, %s]", wallet.AlgorithmEd25519Adr8, wallet.AlgorithmSecp256k1Bip44))
flags.String(cfgAlgorithm, wallet.AlgorithmEd25519Adr8, fmt.Sprintf("Cryptographic algorithm to use for this account [%s, %s, %s]", wallet.AlgorithmEd25519Adr8, wallet.AlgorithmSecp256k1Bip44, wallet.AlgorithmSr25519Adr8))
flags.Uint32(cfgNumber, 0, "Key number to use in the key derivation scheme")

wallet.Register(&fileAccountFactory{
Expand Down
24 changes: 19 additions & 5 deletions wallet/ledger/ledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"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/secp256k1"
"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"
Expand Down Expand Up @@ -216,6 +217,18 @@ func newAccount(cfg *accountConfig) (wallet.Account, error) {
return nil, err
}
pk = secp256k1pk
case wallet.AlgorithmSr25519Adr8:
path = getAdr0008Path(cfg.Number)
rawPk, err := dev.GetPublicKeySr25519(path, false)
if err != nil {
_ = dev.Close()
return nil, err
}
var sr25519pk sr25519.PublicKey
if err := sr25519pk.UnmarshalBinary(rawPk); err != nil {
return nil, err
}
pk = sr25519pk
default:
return nil, fmt.Errorf("unsupported algorithm %s", cfg.Algorithm)
}
Expand Down Expand Up @@ -253,8 +266,7 @@ func (a *ledgerAccount) Address() types.Address {
}

func (a *ledgerAccount) EthAddress() *ethCommon.Address {
switch a.cfg.Algorithm {
case wallet.AlgorithmSecp256k1Bip44, wallet.AlgorithmSecp256k1Raw:
if a.cfg.Algorithm == wallet.AlgorithmSecp256k1Bip44 {
h := sha3.NewLegacyKeccak256()
untaggedPk, _ := a.Signer().Public().(secp256k1.PublicKey).MarshalBinaryUncompressedUntagged()
h.Write(untaggedPk)
Expand All @@ -268,10 +280,12 @@ func (a *ledgerAccount) EthAddress() *ethCommon.Address {

func (a *ledgerAccount) SignatureAddressSpec() types.SignatureAddressSpec {
switch a.cfg.Algorithm {
case "", wallet.AlgorithmEd25519Legacy, wallet.AlgorithmEd25519Adr8, wallet.AlgorithmEd25519Raw:
case "", wallet.AlgorithmEd25519Legacy, wallet.AlgorithmEd25519Adr8:
return types.NewSignatureAddressSpecEd25519(a.Signer().Public().(ed25519.PublicKey))
case wallet.AlgorithmSecp256k1Bip44, wallet.AlgorithmSecp256k1Raw:
case wallet.AlgorithmSecp256k1Bip44:
return types.NewSignatureAddressSpecSecp256k1Eth(a.Signer().Public().(secp256k1.PublicKey))
case wallet.AlgorithmSr25519Adr8:
return types.NewSignatureAddressSpecSr25519(a.Signer().Public().(sr25519.PublicKey))
}
return types.SignatureAddressSpec{}
}
Expand All @@ -283,7 +297,7 @@ func (a *ledgerAccount) UnsafeExport() string {

func init() {
flags := flag.NewFlagSet("", flag.ContinueOnError)
flags.String(cfgAlgorithm, wallet.AlgorithmEd25519Legacy, fmt.Sprintf("Cryptographic algorithm to use for this account [%s, %s, %s]", wallet.AlgorithmEd25519Legacy, wallet.AlgorithmEd25519Adr8, wallet.AlgorithmSecp256k1Bip44))
flags.String(cfgAlgorithm, wallet.AlgorithmEd25519Legacy, fmt.Sprintf("Cryptographic algorithm to use for this account [%s, %s, %s, %s]", wallet.AlgorithmEd25519Legacy, wallet.AlgorithmEd25519Adr8, wallet.AlgorithmSecp256k1Bip44, wallet.AlgorithmSr25519Adr8))
flags.Uint32(cfgNumber, 0, "Key number to use in the derivation scheme")

wallet.Register(&ledgerAccountFactory{
Expand Down
2 changes: 2 additions & 0 deletions wallet/ledger/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ func (ls *ledgerSigner) ContextSign(metadata signature.Context, message []byte)
return ls.dev.SignRtEd25519(ls.path, metadata, message)
case wallet.AlgorithmSecp256k1Bip44:
return ls.dev.SignRtSecp256k1(ls.path, metadata, message)
case wallet.AlgorithmSr25519Adr8:
return ls.dev.SignRtSr25519(ls.path, metadata, message)
}

return nil, fmt.Errorf("ledger: algorithm %s not supported", ls.algorithm)
Expand Down
6 changes: 5 additions & 1 deletion wallet/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
var registeredFactories sync.Map

const (
// AlgorithmEd25519Adr8 is the Ed25519 algorithm using the ADR-8 derivation path (ROSE coin type).
// AlgorithmEd25519Adr8 is the Ed25519 algorithm using the ADR-8 derivation path.
AlgorithmEd25519Adr8 = "ed25519-adr8"
// AlgorithmEd25519Raw is the Ed25519 algorithm using raw private keys.
AlgorithmEd25519Raw = "ed25519-raw"
Expand All @@ -26,6 +26,10 @@ const (
AlgorithmSecp256k1Bip44 = "secp256k1-bip44"
// AlgorithmSecp256k1Raw is the Secp256k1 algorithm using raw private keys.
AlgorithmSecp256k1Raw = "secp256k1-raw"
// AlgorithmSr25519Adr8 is the Sr25519 algorithm using the Ledger-compatible derivation path defined in ADR-8.
AlgorithmSr25519Adr8 = "sr25519-adr8"
// AlgorithmSr25519Raw is the Sr25519 algorithm using raw private keys.
AlgorithmSr25519Raw = "sr25519-raw"
)

// Factory is a factory that supports accounts of a specific kind.
Expand Down

0 comments on commit a3260c7

Please sign in to comment.