In progress: Use Nimbus keystore
This commit is contained in:
parent
db01f0b3e4
commit
d4710faae2
|
@ -23,11 +23,7 @@ func (m *Manager) InitKeystore(keydir string) error {
|
|||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
// TODO: Wire with the Nimbus keystore
|
||||
manager, err := makeAccountManager(keydir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.keystore, err = makeKeyStore(manager)
|
||||
var err error
|
||||
m.keystore, err = makeKeyStore(keydir)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// +build !nimbus
|
||||
|
||||
// TODO: Make independent version for Nimbus
|
||||
|
||||
package account
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
// +build nimbus
|
||||
|
||||
package account
|
||||
|
||||
import (
|
||||
// "io/ioutil"
|
||||
// "os"
|
||||
|
||||
// gethbridge "github.com/status-im/status-go/eth-node/bridge/geth"
|
||||
nimbusbridge "github.com/status-im/status-go/eth-node/bridge/nimbus"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
)
|
||||
|
||||
// // makeAccountManager creates ethereum accounts.Manager with single disk backend and lightweight kdf.
|
||||
// // If keydir is empty new temporary directory with go-ethereum-keystore will be intialized.
|
||||
// func makeAccountManager(keydir string) (manager *accounts.Manager, err error) {
|
||||
// if keydir == "" {
|
||||
// // There is no datadir.
|
||||
// keydir, err = ioutil.TempDir("", "nimbus-keystore")
|
||||
// }
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// if err := os.MkdirAll(keydir, 0700); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// config := accounts.Config{InsecureUnlockAllowed: false}
|
||||
// return accounts.NewManager(&config, keystore.NewKeyStore(keydir, keystore.LightScryptN, keystore.LightScryptP)), nil
|
||||
// }
|
||||
|
||||
// func makeKeyStore(keydir string) (types.KeyStore, error) {
|
||||
// manager, err := makeAccountManager(keydir)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// backends := manager.Backends(keystore.KeyStoreType)
|
||||
// if len(backends) == 0 {
|
||||
// return nil, ErrAccountKeyStoreMissing
|
||||
// }
|
||||
// keyStore, ok := backends[0].(*keystore.KeyStore)
|
||||
// if !ok {
|
||||
// return nil, ErrAccountKeyStoreMissing
|
||||
// }
|
||||
|
||||
// return gethbridge.WrapKeyStore(keyStore), nil
|
||||
// }
|
||||
|
||||
func makeKeyStore(_ string) (types.KeyStore, error) {
|
||||
return nimbusbridge.WrapKeyStore(), nil
|
||||
}
|
|
@ -0,0 +1,263 @@
|
|||
// +build nimbus
|
||||
|
||||
package nimbusbridge
|
||||
|
||||
// https://golang.org/cmd/cgo/
|
||||
|
||||
/*
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <libnimbus.h>
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"unsafe"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/pborman/uuid"
|
||||
|
||||
"github.com/status-im/status-go/eth-node/crypto"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/extkeys"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidSeed = errors.New("seed is invalid")
|
||||
ErrInvalidKeyLen = errors.New("Nimbus serialized extended key length is invalid")
|
||||
)
|
||||
|
||||
type nimbusKeyStoreAdapter struct {
|
||||
}
|
||||
|
||||
// WrapKeyStore creates a types.KeyStore wrapper over the singleton Nimbus node
|
||||
func WrapKeyStore() types.KeyStore {
|
||||
return &nimbusKeyStoreAdapter{}
|
||||
}
|
||||
|
||||
func (k *nimbusKeyStoreAdapter) ImportECDSA(priv *ecdsa.PrivateKey, passphrase string) (types.Account, error) {
|
||||
fmt.Println("ImportECDSA")
|
||||
panic("ImportECDSA")
|
||||
|
||||
var privateKeyC unsafe.Pointer
|
||||
if priv != nil {
|
||||
privateKeyC = C.CBytes(crypto.FromECDSA(priv))
|
||||
defer C.free(privateKeyC)
|
||||
}
|
||||
passphraseC := C.CString(passphrase)
|
||||
defer C.free(unsafe.Pointer(passphraseC))
|
||||
|
||||
var nimbusAccount C.account
|
||||
if !C.nimbus_keystore_import_ecdsa((*C.uchar)(privateKeyC), passphraseC, &nimbusAccount) {
|
||||
return types.Account{}, errors.New("failed to import ECDSA private key")
|
||||
}
|
||||
return accountFrom(&nimbusAccount), nil
|
||||
}
|
||||
|
||||
func (k *nimbusKeyStoreAdapter) ImportSingleExtendedKey(extKey *extkeys.ExtendedKey, passphrase string) (types.Account, error) {
|
||||
fmt.Println("ImportSingleExtendedKey")
|
||||
panic("ImportSingleExtendedKey")
|
||||
|
||||
extKeyJSONC := C.CString(extKey.String())
|
||||
defer C.free(unsafe.Pointer(extKeyJSONC))
|
||||
passphraseC := C.CString(passphrase)
|
||||
defer C.free(unsafe.Pointer(passphraseC))
|
||||
|
||||
var nimbusAccount C.account
|
||||
if !C.nimbus_keystore_import_single_extendedkey(extKeyJSONC, passphraseC, &nimbusAccount) {
|
||||
return types.Account{}, errors.New("failed to import extended key")
|
||||
}
|
||||
return accountFrom(&nimbusAccount), nil
|
||||
}
|
||||
|
||||
func (k *nimbusKeyStoreAdapter) ImportExtendedKeyForPurpose(keyPurpose extkeys.KeyPurpose, extKey *extkeys.ExtendedKey, passphrase string) (types.Account, error) {
|
||||
fmt.Println("ImportExtendedKeyForPurpose")
|
||||
|
||||
passphraseC := C.CString(passphrase)
|
||||
defer C.free(unsafe.Pointer(passphraseC))
|
||||
extKeyJSONC := C.CString(extKey.String())
|
||||
defer C.free(unsafe.Pointer(extKeyJSONC))
|
||||
|
||||
var nimbusAccount C.account
|
||||
if !C.nimbus_keystore_import_extendedkeyforpurpose(C.int(keyPurpose), extKeyJSONC, passphraseC, &nimbusAccount) {
|
||||
return types.Account{}, errors.New("failed to import extended key")
|
||||
}
|
||||
return accountFrom(&nimbusAccount), nil
|
||||
}
|
||||
|
||||
func (k *nimbusKeyStoreAdapter) AccountDecryptedKey(a types.Account, auth string) (types.Account, *types.Key, error) {
|
||||
fmt.Println("AccountDecryptedKey")
|
||||
panic("AccountDecryptedKey")
|
||||
|
||||
authC := C.CString(auth)
|
||||
defer C.free(unsafe.Pointer(authC))
|
||||
|
||||
var nimbusAccount C.account
|
||||
err := nimbusAccountFrom(a, &nimbusAccount)
|
||||
if err != nil {
|
||||
return types.Account{}, nil, err
|
||||
}
|
||||
|
||||
var nimbusKey C.key
|
||||
if !C.nimbus_keystore_account_decrypted_key(authC, &nimbusAccount, &nimbusKey) {
|
||||
return types.Account{}, nil, errors.New("failed to decrypt account key")
|
||||
}
|
||||
key, err := keyFrom(&nimbusKey)
|
||||
if err != nil {
|
||||
return types.Account{}, nil, err
|
||||
}
|
||||
return accountFrom(&nimbusAccount), key, nil
|
||||
}
|
||||
|
||||
func (k *nimbusKeyStoreAdapter) Delete(a types.Account, auth string) error {
|
||||
fmt.Println("Delete")
|
||||
|
||||
var nimbusAccount C.account
|
||||
err := nimbusAccountFrom(a, &nimbusAccount)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authC := C.CString(auth)
|
||||
defer C.free(unsafe.Pointer(authC))
|
||||
|
||||
if !C.nimbus_keystore_delete(&nimbusAccount, authC) {
|
||||
return errors.New("failed to delete account")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func nimbusAccountFrom(account types.Account, nimbusAccount *C.account) error {
|
||||
fmt.Println("nimbusAccountFrom")
|
||||
err := copyAddressToCBuffer(&nimbusAccount.address[0], account.Address.Bytes())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if account.URL == "" {
|
||||
nimbusAccount.url[0] = C.char(0)
|
||||
} else if len(account.URL) >= C.URL_LEN {
|
||||
return errors.New("URL is too long to fit in Nimbus struct")
|
||||
} else {
|
||||
copyURLToCBuffer(&nimbusAccount.url[0], account.URL)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func accountFrom(nimbusAccount *C.account) types.Account {
|
||||
return types.Account{
|
||||
Address: types.BytesToAddress(C.GoBytes(unsafe.Pointer(&nimbusAccount.address[0]), C.ADDRESS_LEN)),
|
||||
URL: C.GoString(&nimbusAccount.url[0]),
|
||||
}
|
||||
}
|
||||
|
||||
// copyAddressToCBuffer copies a Go buffer to a C buffer without allocating new memory
|
||||
func copyAddressToCBuffer(dst *C.uchar, src []byte) error {
|
||||
if len(src) != C.ADDRESS_LEN {
|
||||
return errors.New("invalid buffer size")
|
||||
}
|
||||
|
||||
p := (*[C.ADDRESS_LEN]C.uchar)(unsafe.Pointer(dst))
|
||||
for index, b := range src {
|
||||
p[index] = C.uchar(b)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// copyURLToCBuffer copies a Go buffer to a C buffer without allocating new memory
|
||||
func copyURLToCBuffer(dst *C.char, src string) error {
|
||||
if len(src)+1 > C.URL_LEN {
|
||||
return errors.New("URL is too long to fit in Nimbus struct")
|
||||
}
|
||||
|
||||
p := (*[C.URL_LEN]C.uchar)(unsafe.Pointer(dst))
|
||||
for index := 0; index <= len(src); index++ {
|
||||
p[index] = C.uchar(src[index])
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func keyFrom(k *C.key) (*types.Key, error) {
|
||||
fmt.Println("keyFrom")
|
||||
if k == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var err error
|
||||
key := types.Key{
|
||||
Id: uuid.Parse(C.GoString(&k.id[0])),
|
||||
}
|
||||
key.Address = types.BytesToAddress(C.GoBytes(unsafe.Pointer(&k.address[0]), C.ADDRESS_LEN))
|
||||
key.PrivateKey, err = crypto.ToECDSA(C.GoBytes(unsafe.Pointer(&k.privateKeyID[0]), C.PRIVKEY_LEN))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key.ExtendedKey, err = newExtKeyFromBuffer(C.GoBytes(unsafe.Pointer(&k.extKey[0]), C.EXTKEY_LEN))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &key, err
|
||||
}
|
||||
|
||||
// newExtKeyFromBuffer returns a new extended key instance from a serialized
|
||||
// extended key.
|
||||
func newExtKeyFromBuffer(key []byte) (*extkeys.ExtendedKey, error) {
|
||||
if len(key) == 0 {
|
||||
return &extkeys.ExtendedKey{}, nil
|
||||
}
|
||||
|
||||
if len(key) != C.EXTKEY_LEN {
|
||||
return nil, ErrInvalidKeyLen
|
||||
}
|
||||
|
||||
// The serialized format is:
|
||||
// version (4) || depth (1) || parent fingerprint (4)) ||
|
||||
// child num (4) || chain code (32) || key data (33)
|
||||
|
||||
payload := key
|
||||
|
||||
// Deserialize each of the payload fields.
|
||||
version := payload[:4]
|
||||
depth := payload[4:5][0]
|
||||
fingerPrint := payload[5:9]
|
||||
childNumber := binary.BigEndian.Uint32(payload[9:13])
|
||||
chainCode := payload[13:45]
|
||||
keyData := payload[45:78]
|
||||
|
||||
// The key data is a private key if it starts with 0x00. Serialized
|
||||
// compressed pubkeys either start with 0x02 or 0x03.
|
||||
isPrivate := keyData[0] == 0x00
|
||||
if isPrivate {
|
||||
// Ensure the private key is valid. It must be within the range
|
||||
// of the order of the secp256k1 curve and not be 0.
|
||||
keyData = keyData[1:]
|
||||
keyNum := new(big.Int).SetBytes(keyData)
|
||||
if keyNum.Cmp(btcec.S256().N) >= 0 || keyNum.Sign() == 0 {
|
||||
return nil, ErrInvalidSeed
|
||||
}
|
||||
} else {
|
||||
// Ensure the public key parses correctly and is actually on the
|
||||
// secp256k1 curve.
|
||||
_, err := btcec.ParsePubKey(keyData, btcec.S256())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &extkeys.ExtendedKey{
|
||||
Version: version,
|
||||
KeyData: keyData,
|
||||
ChainCode: chainCode,
|
||||
FingerPrint: fingerPrint,
|
||||
Depth: depth,
|
||||
ChildNumber: childNumber,
|
||||
IsPrivate: isPrivate,
|
||||
}, nil
|
||||
}
|
|
@ -11,6 +11,7 @@ replace github.com/status-im/status-go/whisper/v6 => ../whisper
|
|||
replace github.com/status-im/status-go/waku => ../waku
|
||||
|
||||
require (
|
||||
github.com/btcsuite/btcd v0.20.1-beta
|
||||
github.com/ethereum/go-ethereum v1.9.5
|
||||
github.com/mattn/go-pointer v0.0.0-20190911064623-a0a44394634f
|
||||
github.com/pborman/uuid v1.2.0
|
||||
|
|
|
@ -31,6 +31,7 @@ github.com/aristanetworks/goarista v0.0.0-20191106175434-873d404c7f40/go.mod h1:
|
|||
github.com/aristanetworks/splunk-hec-go v0.3.3/go.mod h1:1VHO9r17b0K7WmOlLb9nTk/2YanvOEnLMUgsFrxBROc=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/btcsuite/btcd v0.0.0-20181013004428-67e573d211ac/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ=
|
||||
github.com/btcsuite/btcd v0.0.0-20190418232430-6867ff32788a/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8=
|
||||
|
@ -50,7 +51,9 @@ github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46f
|
|||
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
||||
github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU=
|
||||
github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA=
|
||||
github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||
|
@ -103,6 +106,7 @@ github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM
|
|||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
|
||||
|
@ -172,6 +176,7 @@ github.com/mattn/go-pointer v0.0.0-20190911064623-a0a44394634f/go.mod h1:2zXcozF
|
|||
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g=
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
|
||||
|
@ -221,17 +226,18 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
||||
github.com/prometheus/client_golang v1.2.1 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvlsMzzNayLOI=
|
||||
github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
||||
github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY=
|
||||
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8=
|
||||
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
github.com/prometheus/prometheus v0.0.0-20170814170113-3101606756c5/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s=
|
||||
github.com/prometheus/tsdb v0.10.0 h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38ic=
|
||||
|
@ -359,8 +365,7 @@ golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190912141932-bc967efca4b8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
|
263
vendor/github.com/status-im/status-go/eth-node/bridge/nimbus/keystore.go
generated
vendored
Normal file
263
vendor/github.com/status-im/status-go/eth-node/bridge/nimbus/keystore.go
generated
vendored
Normal file
|
@ -0,0 +1,263 @@
|
|||
// +build nimbus
|
||||
|
||||
package nimbusbridge
|
||||
|
||||
// https://golang.org/cmd/cgo/
|
||||
|
||||
/*
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <libnimbus.h>
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"unsafe"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/pborman/uuid"
|
||||
|
||||
"github.com/status-im/status-go/eth-node/crypto"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/extkeys"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidSeed = errors.New("seed is invalid")
|
||||
ErrInvalidKeyLen = errors.New("Nimbus serialized extended key length is invalid")
|
||||
)
|
||||
|
||||
type nimbusKeyStoreAdapter struct {
|
||||
}
|
||||
|
||||
// WrapKeyStore creates a types.KeyStore wrapper over the singleton Nimbus node
|
||||
func WrapKeyStore() types.KeyStore {
|
||||
return &nimbusKeyStoreAdapter{}
|
||||
}
|
||||
|
||||
func (k *nimbusKeyStoreAdapter) ImportECDSA(priv *ecdsa.PrivateKey, passphrase string) (types.Account, error) {
|
||||
fmt.Println("ImportECDSA")
|
||||
panic("ImportECDSA")
|
||||
|
||||
var privateKeyC unsafe.Pointer
|
||||
if priv != nil {
|
||||
privateKeyC = C.CBytes(crypto.FromECDSA(priv))
|
||||
defer C.free(privateKeyC)
|
||||
}
|
||||
passphraseC := C.CString(passphrase)
|
||||
defer C.free(unsafe.Pointer(passphraseC))
|
||||
|
||||
var nimbusAccount C.account
|
||||
if !C.nimbus_keystore_import_ecdsa((*C.uchar)(privateKeyC), passphraseC, &nimbusAccount) {
|
||||
return types.Account{}, errors.New("failed to import ECDSA private key")
|
||||
}
|
||||
return accountFrom(&nimbusAccount), nil
|
||||
}
|
||||
|
||||
func (k *nimbusKeyStoreAdapter) ImportSingleExtendedKey(extKey *extkeys.ExtendedKey, passphrase string) (types.Account, error) {
|
||||
fmt.Println("ImportSingleExtendedKey")
|
||||
panic("ImportSingleExtendedKey")
|
||||
|
||||
extKeyJSONC := C.CString(extKey.String())
|
||||
defer C.free(unsafe.Pointer(extKeyJSONC))
|
||||
passphraseC := C.CString(passphrase)
|
||||
defer C.free(unsafe.Pointer(passphraseC))
|
||||
|
||||
var nimbusAccount C.account
|
||||
if !C.nimbus_keystore_import_single_extendedkey(extKeyJSONC, passphraseC, &nimbusAccount) {
|
||||
return types.Account{}, errors.New("failed to import extended key")
|
||||
}
|
||||
return accountFrom(&nimbusAccount), nil
|
||||
}
|
||||
|
||||
func (k *nimbusKeyStoreAdapter) ImportExtendedKeyForPurpose(keyPurpose extkeys.KeyPurpose, extKey *extkeys.ExtendedKey, passphrase string) (types.Account, error) {
|
||||
fmt.Println("ImportExtendedKeyForPurpose")
|
||||
|
||||
passphraseC := C.CString(passphrase)
|
||||
defer C.free(unsafe.Pointer(passphraseC))
|
||||
extKeyJSONC := C.CString(extKey.String())
|
||||
defer C.free(unsafe.Pointer(extKeyJSONC))
|
||||
|
||||
var nimbusAccount C.account
|
||||
if !C.nimbus_keystore_import_extendedkeyforpurpose(C.int(keyPurpose), extKeyJSONC, passphraseC, &nimbusAccount) {
|
||||
return types.Account{}, errors.New("failed to import extended key")
|
||||
}
|
||||
return accountFrom(&nimbusAccount), nil
|
||||
}
|
||||
|
||||
func (k *nimbusKeyStoreAdapter) AccountDecryptedKey(a types.Account, auth string) (types.Account, *types.Key, error) {
|
||||
fmt.Println("AccountDecryptedKey")
|
||||
panic("AccountDecryptedKey")
|
||||
|
||||
authC := C.CString(auth)
|
||||
defer C.free(unsafe.Pointer(authC))
|
||||
|
||||
var nimbusAccount C.account
|
||||
err := nimbusAccountFrom(a, &nimbusAccount)
|
||||
if err != nil {
|
||||
return types.Account{}, nil, err
|
||||
}
|
||||
|
||||
var nimbusKey C.key
|
||||
if !C.nimbus_keystore_account_decrypted_key(authC, &nimbusAccount, &nimbusKey) {
|
||||
return types.Account{}, nil, errors.New("failed to decrypt account key")
|
||||
}
|
||||
key, err := keyFrom(&nimbusKey)
|
||||
if err != nil {
|
||||
return types.Account{}, nil, err
|
||||
}
|
||||
return accountFrom(&nimbusAccount), key, nil
|
||||
}
|
||||
|
||||
func (k *nimbusKeyStoreAdapter) Delete(a types.Account, auth string) error {
|
||||
fmt.Println("Delete")
|
||||
|
||||
var nimbusAccount C.account
|
||||
err := nimbusAccountFrom(a, &nimbusAccount)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authC := C.CString(auth)
|
||||
defer C.free(unsafe.Pointer(authC))
|
||||
|
||||
if !C.nimbus_keystore_delete(&nimbusAccount, authC) {
|
||||
return errors.New("failed to delete account")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func nimbusAccountFrom(account types.Account, nimbusAccount *C.account) error {
|
||||
fmt.Println("nimbusAccountFrom")
|
||||
err := copyAddressToCBuffer(&nimbusAccount.address[0], account.Address.Bytes())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if account.URL == "" {
|
||||
nimbusAccount.url[0] = C.char(0)
|
||||
} else if len(account.URL) >= C.URL_LEN {
|
||||
return errors.New("URL is too long to fit in Nimbus struct")
|
||||
} else {
|
||||
copyURLToCBuffer(&nimbusAccount.url[0], account.URL)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func accountFrom(nimbusAccount *C.account) types.Account {
|
||||
return types.Account{
|
||||
Address: types.BytesToAddress(C.GoBytes(unsafe.Pointer(&nimbusAccount.address[0]), C.ADDRESS_LEN)),
|
||||
URL: C.GoString(&nimbusAccount.url[0]),
|
||||
}
|
||||
}
|
||||
|
||||
// copyAddressToCBuffer copies a Go buffer to a C buffer without allocating new memory
|
||||
func copyAddressToCBuffer(dst *C.uchar, src []byte) error {
|
||||
if len(src) != C.ADDRESS_LEN {
|
||||
return errors.New("invalid buffer size")
|
||||
}
|
||||
|
||||
p := (*[C.ADDRESS_LEN]C.uchar)(unsafe.Pointer(dst))
|
||||
for index, b := range src {
|
||||
p[index] = C.uchar(b)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// copyURLToCBuffer copies a Go buffer to a C buffer without allocating new memory
|
||||
func copyURLToCBuffer(dst *C.char, src string) error {
|
||||
if len(src)+1 > C.URL_LEN {
|
||||
return errors.New("URL is too long to fit in Nimbus struct")
|
||||
}
|
||||
|
||||
p := (*[C.URL_LEN]C.uchar)(unsafe.Pointer(dst))
|
||||
for index := 0; index <= len(src); index++ {
|
||||
p[index] = C.uchar(src[index])
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func keyFrom(k *C.key) (*types.Key, error) {
|
||||
fmt.Println("keyFrom")
|
||||
if k == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var err error
|
||||
key := types.Key{
|
||||
Id: uuid.Parse(C.GoString(&k.id[0])),
|
||||
}
|
||||
key.Address = types.BytesToAddress(C.GoBytes(unsafe.Pointer(&k.address[0]), C.ADDRESS_LEN))
|
||||
key.PrivateKey, err = crypto.ToECDSA(C.GoBytes(unsafe.Pointer(&k.privateKeyID[0]), C.PRIVKEY_LEN))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key.ExtendedKey, err = newExtKeyFromBuffer(C.GoBytes(unsafe.Pointer(&k.extKey[0]), C.EXTKEY_LEN))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &key, err
|
||||
}
|
||||
|
||||
// newExtKeyFromBuffer returns a new extended key instance from a serialized
|
||||
// extended key.
|
||||
func newExtKeyFromBuffer(key []byte) (*extkeys.ExtendedKey, error) {
|
||||
if len(key) == 0 {
|
||||
return &extkeys.ExtendedKey{}, nil
|
||||
}
|
||||
|
||||
if len(key) != C.EXTKEY_LEN {
|
||||
return nil, ErrInvalidKeyLen
|
||||
}
|
||||
|
||||
// The serialized format is:
|
||||
// version (4) || depth (1) || parent fingerprint (4)) ||
|
||||
// child num (4) || chain code (32) || key data (33)
|
||||
|
||||
payload := key
|
||||
|
||||
// Deserialize each of the payload fields.
|
||||
version := payload[:4]
|
||||
depth := payload[4:5][0]
|
||||
fingerPrint := payload[5:9]
|
||||
childNumber := binary.BigEndian.Uint32(payload[9:13])
|
||||
chainCode := payload[13:45]
|
||||
keyData := payload[45:78]
|
||||
|
||||
// The key data is a private key if it starts with 0x00. Serialized
|
||||
// compressed pubkeys either start with 0x02 or 0x03.
|
||||
isPrivate := keyData[0] == 0x00
|
||||
if isPrivate {
|
||||
// Ensure the private key is valid. It must be within the range
|
||||
// of the order of the secp256k1 curve and not be 0.
|
||||
keyData = keyData[1:]
|
||||
keyNum := new(big.Int).SetBytes(keyData)
|
||||
if keyNum.Cmp(btcec.S256().N) >= 0 || keyNum.Sign() == 0 {
|
||||
return nil, ErrInvalidSeed
|
||||
}
|
||||
} else {
|
||||
// Ensure the public key parses correctly and is actually on the
|
||||
// secp256k1 curve.
|
||||
_, err := btcec.ParsePubKey(keyData, btcec.S256())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &extkeys.ExtendedKey{
|
||||
Version: version,
|
||||
KeyData: keyData,
|
||||
ChainCode: chainCode,
|
||||
FingerPrint: fingerPrint,
|
||||
Depth: depth,
|
||||
ChildNumber: childNumber,
|
||||
IsPrivate: isPrivate,
|
||||
}, nil
|
||||
}
|
Loading…
Reference in New Issue