Skip to content

Commit

Permalink
feat(wallet): Add file-based sr25519-adr8 support
Browse files Browse the repository at this point in the history
  • Loading branch information
matevz committed Aug 8, 2023
1 parent 80ee834 commit 8536e89
Showing 1 changed file with 94 additions and 8 deletions.
102 changes: 94 additions & 8 deletions wallet/file/sr25519.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
package file

import (
"crypto/hmac"
"crypto/sha512"
"encoding/binary"
"fmt"

"github.com/oasisprotocol/oasis-core/go/common/crypto/sakg"
"github.com/oasisprotocol/oasis-core/go/common/crypto/signature"
"github.com/oasisprotocol/oasis-core/go/common/crypto/signature/signers/memory"
"github.com/tyler-smith/go-bip39"

"github.com/oasisprotocol/curve25519-voi/primitives/sr25519"
"github.com/oasisprotocol/oasis-core/go/common/crypto/sakg"
"github.com/oasisprotocol/oasis-core/go/common/crypto/slip10"
sdkSignature "github.com/oasisprotocol/oasis-sdk/client-sdk/go/crypto/signature"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/crypto/signature/sr25519"
"github.com/tyler-smith/go-bip39"
sdkSr25519 "github.com/oasisprotocol/oasis-sdk/client-sdk/go/crypto/signature/sr25519"
)

// Sr25519FromMnemonic derives a signer using ADR-8 from given mnemonic.
@@ -27,7 +33,7 @@ func Sr25519FromMnemonic(mnemonic string, number uint32) (sdkSignature.Signer, e

seed := bip39.NewSeed(mnemonic, "")

signer, chainCode, err := slip10.NewMasterKey(seed)
_, chainCode, skBinary, err := newMasterKey(seed)
if err != nil {
return nil, fmt.Errorf("sakg: error deriving master key: %w", err)
}
@@ -38,16 +44,96 @@ func Sr25519FromMnemonic(mnemonic string, number uint32) (sdkSignature.Signer, e
return nil, fmt.Errorf("sakg: error creating BIP-0032 path %s: %w", pathStr, err)
}

var signer sdkSignature.Signer
for _, index := range path {
signer, chainCode, err = slip10.NewChildKey(signer, chainCode, index)
signer, chainCode, skBinary, err = newChildKey(skBinary, chainCode, index)
if err != nil {
return nil, fmt.Errorf("sakg: error deriving child key: %w", err)
}
}

sr25519signer, err := sr25519.NewSigner(signer.(signature.UnsafeSigner).UnsafeBytes())
return signer, nil
}

func newMasterKey(seed []byte) (sdkSignature.Signer, slip10.ChainCode, []byte, error) {
// Let S be a seed byte sequence of 128 to 512 bits in length.
if sLen := len(seed); sLen < slip10.SeedMinSize || sLen > slip10.SeedMaxSize {
return nil, slip10.ChainCode{}, nil, fmt.Errorf("slip10: invalid seed")
}

// 1. Calculate I = HMAC-SHA512(Key = Curve, Data = S)
mac := hmac.New(sha512.New, []byte("ed25519 seed"))
_, _ = mac.Write(seed)
I := mac.Sum(nil)

// 2. Split I into two 32-byte sequences, IL and IR.
// 3. Use parse256(IL) as master secret key, and IR as master chain code.
return splitDigest(I)
}

func newChildKey(kPar []byte, cPar slip10.ChainCode, index uint32) (sdkSignature.Signer, slip10.ChainCode, []byte, error) {
if len(kPar) < memory.SeedSize {
return nil, slip10.ChainCode{}, nil, fmt.Errorf("slip10: invalid parent key")
}

// 1. Check whether i >= 2^31 (whether the child is a hardened key).
if index < 1<<31 {
// If not (normal child):
// If curve is ed25519: return failure.
return nil, slip10.ChainCode{}, nil, fmt.Errorf("slip10: non-hardened keys not supported")
}

// If so (hardened child):
// let I = HMAC-SHA512(Key = cpar, Data = 0x00 || ser256(kpar) || ser32(i)).
// (Note: The 0x00 pads the private key to make it 33 bytes long.)
var b [4]byte
mac := hmac.New(sha512.New, cPar[:])
_, _ = mac.Write(b[0:1]) // 0x00
_, _ = mac.Write(kPar[:memory.SeedSize]) // ser256(kPar)
binary.BigEndian.PutUint32(b[:], index) // Note: The spec neglects to define ser32.
_, _ = mac.Write(b[:]) // ser32(i)
I := mac.Sum(nil)

// 2. Split I into two 32-byte sequences, IL and IR.
// 3. The returned chain code ci is IR.
// 4. If curve is ed25519: The returned child key ki is parse256(IL).
return splitDigest(I)
}

func splitDigest(digest []byte) (sdkSignature.Signer, slip10.ChainCode, []byte, error) {
IL, IR := digest[:32], digest[32:]

var chainCode slip10.ChainCode

msk, err := sr25519.NewMiniSecretKeyFromBytes(IL)
if err != nil {
return nil, chainCode, nil, err
}
sk := msk.ExpandEd25519()
signer := sdkSr25519.NewSignerFromKeyPair(sk.KeyPair())
copy(chainCode[:], IR)

skBinary, err := sk.MarshalBinary()
if err != nil {
return nil, chainCode, nil, err
}

return signer, chainCode, skBinary, nil
}

func splitDigestOrig(digest []byte) (sdkSignature.Signer, slip10.ChainCode, []byte, error) {
IL, IR := digest[:32], digest[32:]

var chainCode slip10.ChainCode
signer, err := memory.NewFromSeed(IL)
if err != nil {
return nil, chainCode, nil, err
}
copy(chainCode[:], IR)

sr25519signer, err := sdkSr25519.NewSigner(signer.(signature.UnsafeSigner).UnsafeBytes())
if err != nil {
return nil, err
return nil, chainCode, nil, err
}
return sr25519signer, nil
return sr25519signer, chainCode, signer.(signature.UnsafeSigner).UnsafeBytes(), nil
}

0 comments on commit 8536e89

Please sign in to comment.