Skip to content

Commit a3260c7

Browse files
authored
Merge pull request #109 from oasisprotocol/matevz/feature/sr25519-ledger
Sr25519 support for Ledger
2 parents 5c27e5d + faeb4ab commit a3260c7

4 files changed

Lines changed: 57 additions & 11 deletions

File tree

wallet/file/file.go

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ import (
2020
"github.com/oasisprotocol/deoxysii"
2121
"github.com/oasisprotocol/oasis-core/go/common/crypto/sakg"
2222
coreSignature "github.com/oasisprotocol/oasis-core/go/common/crypto/signature"
23-
2423
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/crypto/signature"
2524
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/crypto/signature/ed25519"
2625
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/crypto/signature/secp256k1"
26+
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/crypto/signature/sr25519"
2727
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/types"
2828

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

5151
switch *kind {
5252
case wallet.ImportKindMnemonic:
5353
return []string{wallet.AlgorithmEd25519Adr8, wallet.AlgorithmSecp256k1Bip44}
5454
case wallet.ImportKindPrivateKey:
55-
return []string{wallet.AlgorithmEd25519Raw, wallet.AlgorithmSecp256k1Raw}
55+
return []string{wallet.AlgorithmEd25519Raw, wallet.AlgorithmSecp256k1Raw, wallet.AlgorithmSr25519Raw}
5656
default:
5757
return []string{}
5858
}
@@ -258,6 +258,8 @@ func (af *fileAccountFactory) DataPrompt(kind wallet.ImportKind, rawCfg map[stri
258258
return &survey.Multiline{Message: "Private key (base64-encoded):"}
259259
case wallet.AlgorithmSecp256k1Raw:
260260
return &survey.Multiline{Message: "Private key (hex-encoded):"}
261+
case wallet.AlgorithmSr25519Raw:
262+
return &survey.Multiline{Message: "Private key (base64-encoded):"}
261263
default:
262264
return nil
263265
}
@@ -288,6 +290,12 @@ func (af *fileAccountFactory) DataValidator(kind wallet.ImportKind, rawCfg map[s
288290
if err != nil {
289291
return fmt.Errorf("private key must be hex-encoded (without leading 0x): %w", err)
290292
}
293+
case wallet.AlgorithmSr25519Raw:
294+
// Ensure the private key is base64 encoded.
295+
_, err := base64.StdEncoding.DecodeString(ans.(string))
296+
if err != nil {
297+
return fmt.Errorf("private key must be base64-encoded: %w", err)
298+
}
291299
default:
292300
return fmt.Errorf("unsupported algorithm for %s: %s", wallet.ImportKindPrivateKey, cfg.Algorithm)
293301
}
@@ -427,7 +435,7 @@ func (af *fileAccountFactory) Import(name string, passphrase string, rawCfg map[
427435
}
428436
case wallet.ImportKindPrivateKey:
429437
switch cfg.Algorithm {
430-
case wallet.AlgorithmEd25519Raw, wallet.AlgorithmSecp256k1Raw:
438+
case wallet.AlgorithmEd25519Raw, wallet.AlgorithmSecp256k1Raw, wallet.AlgorithmSr25519Raw:
431439
default:
432440
return nil, fmt.Errorf("algorithm '%s' does not support import from private key", cfg.Algorithm)
433441
}
@@ -512,6 +520,22 @@ func newAccount(state *secretState, cfg *accountConfig) (wallet.Account, error)
512520
return nil, fmt.Errorf("failed to initialize signer: %w", err)
513521
}
514522

523+
return &fileAccount{
524+
cfg: cfg,
525+
state: state,
526+
signer: signer,
527+
}, nil
528+
case wallet.AlgorithmSr25519Raw:
529+
// For Sr25519-Raw use the raw private key.
530+
dataRaw, err := base64.StdEncoding.DecodeString(state.Data)
531+
if err != nil {
532+
return nil, err
533+
}
534+
signer, err := sr25519.NewSigner(dataRaw)
535+
if err != nil {
536+
return nil, err
537+
}
538+
515539
return &fileAccount{
516540
cfg: cfg,
517541
state: state,
@@ -561,6 +585,8 @@ func (a *fileAccount) SignatureAddressSpec() types.SignatureAddressSpec {
561585
return types.NewSignatureAddressSpecEd25519(a.Signer().Public().(ed25519.PublicKey))
562586
case wallet.AlgorithmSecp256k1Bip44, wallet.AlgorithmSecp256k1Raw:
563587
return types.NewSignatureAddressSpecSecp256k1Eth(a.Signer().Public().(secp256k1.PublicKey))
588+
case wallet.AlgorithmSr25519Adr8, wallet.AlgorithmSr25519Raw:
589+
return types.NewSignatureAddressSpecSr25519(a.Signer().Public().(sr25519.PublicKey))
564590
default:
565591
return types.SignatureAddressSpec{}
566592
}
@@ -572,7 +598,7 @@ func (a *fileAccount) UnsafeExport() string {
572598

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

578604
wallet.Register(&fileAccountFactory{

wallet/ledger/ledger.go

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/crypto/signature"
1414
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/crypto/signature/ed25519"
1515
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/crypto/signature/secp256k1"
16+
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/crypto/signature/sr25519"
1617
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/types"
1718

1819
"github.com/oasisprotocol/cli/wallet"
@@ -216,6 +217,18 @@ func newAccount(cfg *accountConfig) (wallet.Account, error) {
216217
return nil, err
217218
}
218219
pk = secp256k1pk
220+
case wallet.AlgorithmSr25519Adr8:
221+
path = getAdr0008Path(cfg.Number)
222+
rawPk, err := dev.GetPublicKeySr25519(path, false)
223+
if err != nil {
224+
_ = dev.Close()
225+
return nil, err
226+
}
227+
var sr25519pk sr25519.PublicKey
228+
if err := sr25519pk.UnmarshalBinary(rawPk); err != nil {
229+
return nil, err
230+
}
231+
pk = sr25519pk
219232
default:
220233
return nil, fmt.Errorf("unsupported algorithm %s", cfg.Algorithm)
221234
}
@@ -253,8 +266,7 @@ func (a *ledgerAccount) Address() types.Address {
253266
}
254267

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

269281
func (a *ledgerAccount) SignatureAddressSpec() types.SignatureAddressSpec {
270282
switch a.cfg.Algorithm {
271-
case "", wallet.AlgorithmEd25519Legacy, wallet.AlgorithmEd25519Adr8, wallet.AlgorithmEd25519Raw:
283+
case "", wallet.AlgorithmEd25519Legacy, wallet.AlgorithmEd25519Adr8:
272284
return types.NewSignatureAddressSpecEd25519(a.Signer().Public().(ed25519.PublicKey))
273-
case wallet.AlgorithmSecp256k1Bip44, wallet.AlgorithmSecp256k1Raw:
285+
case wallet.AlgorithmSecp256k1Bip44:
274286
return types.NewSignatureAddressSpecSecp256k1Eth(a.Signer().Public().(secp256k1.PublicKey))
287+
case wallet.AlgorithmSr25519Adr8:
288+
return types.NewSignatureAddressSpecSr25519(a.Signer().Public().(sr25519.PublicKey))
275289
}
276290
return types.SignatureAddressSpec{}
277291
}
@@ -283,7 +297,7 @@ func (a *ledgerAccount) UnsafeExport() string {
283297

284298
func init() {
285299
flags := flag.NewFlagSet("", flag.ContinueOnError)
286-
flags.String(cfgAlgorithm, wallet.AlgorithmEd25519Legacy, fmt.Sprintf("Cryptographic algorithm to use for this account [%s, %s, %s]", wallet.AlgorithmEd25519Legacy, wallet.AlgorithmEd25519Adr8, wallet.AlgorithmSecp256k1Bip44))
300+
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))
287301
flags.Uint32(cfgNumber, 0, "Key number to use in the derivation scheme")
288302

289303
wallet.Register(&ledgerAccountFactory{

wallet/ledger/signer.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ func (ls *ledgerSigner) ContextSign(metadata signature.Context, message []byte)
5858
return ls.dev.SignRtEd25519(ls.path, metadata, message)
5959
case wallet.AlgorithmSecp256k1Bip44:
6060
return ls.dev.SignRtSecp256k1(ls.path, metadata, message)
61+
case wallet.AlgorithmSr25519Adr8:
62+
return ls.dev.SignRtSr25519(ls.path, metadata, message)
6163
}
6264

6365
return nil, fmt.Errorf("ledger: algorithm %s not supported", ls.algorithm)

wallet/wallet.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616
var registeredFactories sync.Map
1717

1818
const (
19-
// AlgorithmEd25519Adr8 is the Ed25519 algorithm using the ADR-8 derivation path (ROSE coin type).
19+
// AlgorithmEd25519Adr8 is the Ed25519 algorithm using the ADR-8 derivation path.
2020
AlgorithmEd25519Adr8 = "ed25519-adr8"
2121
// AlgorithmEd25519Raw is the Ed25519 algorithm using raw private keys.
2222
AlgorithmEd25519Raw = "ed25519-raw"
@@ -26,6 +26,10 @@ const (
2626
AlgorithmSecp256k1Bip44 = "secp256k1-bip44"
2727
// AlgorithmSecp256k1Raw is the Secp256k1 algorithm using raw private keys.
2828
AlgorithmSecp256k1Raw = "secp256k1-raw"
29+
// AlgorithmSr25519Adr8 is the Sr25519 algorithm using the Ledger-compatible derivation path defined in ADR-8.
30+
AlgorithmSr25519Adr8 = "sr25519-adr8"
31+
// AlgorithmSr25519Raw is the Sr25519 algorithm using raw private keys.
32+
AlgorithmSr25519Raw = "sr25519-raw"
2933
)
3034

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

0 commit comments

Comments
 (0)