mirror of https://github.com/ethereum/go-ethereum
commit
29f613ef84
@ -0,0 +1,35 @@ |
||||
package ethcrypto |
||||
|
||||
import ( |
||||
"code.google.com/p/go.crypto/ripemd160" |
||||
"crypto/sha256" |
||||
"github.com/obscuren/sha3" |
||||
"math/big" |
||||
) |
||||
|
||||
func Sha256Bin(data []byte) []byte { |
||||
hash := sha256.Sum256(data) |
||||
|
||||
return hash[:] |
||||
} |
||||
|
||||
func Ripemd160(data []byte) []byte { |
||||
ripemd := ripemd160.New() |
||||
ripemd.Write(data) |
||||
|
||||
return ripemd.Sum(nil) |
||||
} |
||||
|
||||
func Sha3Bin(data []byte) []byte { |
||||
d := sha3.NewKeccak256() |
||||
d.Write(data) |
||||
|
||||
return d.Sum(nil) |
||||
} |
||||
|
||||
// Creates an ethereum address given the bytes and the nonce
|
||||
func CreateAddress(b []byte, nonce *big.Int) []byte { |
||||
addrBytes := append(b, nonce.Bytes()...) |
||||
|
||||
return Sha3Bin(addrBytes)[12:] |
||||
} |
@ -0,0 +1,129 @@ |
||||
package ethcrypto |
||||
|
||||
import ( |
||||
"fmt" |
||||
"github.com/ethereum/eth-go/ethutil" |
||||
"sync" |
||||
) |
||||
|
||||
type KeyManager struct { |
||||
keyRing *KeyRing |
||||
session string |
||||
keyStore KeyStore // interface
|
||||
keyRings map[string]*KeyRing // cache
|
||||
keyPair *KeyPair |
||||
} |
||||
|
||||
func NewDBKeyManager(db ethutil.Database) *KeyManager { |
||||
return &KeyManager{keyStore: &DBKeyStore{db: db}, keyRings: make(map[string]*KeyRing)} |
||||
} |
||||
|
||||
func NewFileKeyManager(basedir string) *KeyManager { |
||||
return &KeyManager{keyStore: &FileKeyStore{basedir: basedir}, keyRings: make(map[string]*KeyRing)} |
||||
} |
||||
|
||||
func (k *KeyManager) KeyPair() *KeyPair { |
||||
return k.keyPair |
||||
} |
||||
|
||||
func (k *KeyManager) KeyRing() *KeyPair { |
||||
return k.keyPair |
||||
} |
||||
|
||||
func (k *KeyManager) PrivateKey() []byte { |
||||
return k.keyPair.PrivateKey |
||||
} |
||||
|
||||
func (k *KeyManager) PublicKey() []byte { |
||||
return k.keyPair.PublicKey |
||||
} |
||||
|
||||
func (k *KeyManager) Address() []byte { |
||||
return k.keyPair.Address() |
||||
} |
||||
|
||||
func (k *KeyManager) save(session string, keyRing *KeyRing) error { |
||||
err := k.keyStore.Save(session, keyRing) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
k.keyRings[session] = keyRing |
||||
return nil |
||||
} |
||||
|
||||
func (k *KeyManager) load(session string) (*KeyRing, error) { |
||||
keyRing, found := k.keyRings[session] |
||||
if !found { |
||||
var err error |
||||
keyRing, err = k.keyStore.Load(session) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
} |
||||
return keyRing, nil |
||||
} |
||||
|
||||
func cursorError(cursor int, len int) error { |
||||
return fmt.Errorf("cursor %d out of range (0..%d)", cursor, len) |
||||
} |
||||
|
||||
func (k *KeyManager) reset(session string, cursor int, keyRing *KeyRing) error { |
||||
if cursor >= keyRing.Len() { |
||||
return cursorError(cursor, keyRing.Len()) |
||||
} |
||||
lock := &sync.Mutex{} |
||||
lock.Lock() |
||||
defer lock.Unlock() |
||||
err := k.save(session, keyRing) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
k.session = session |
||||
k.keyRing = keyRing |
||||
k.keyPair = keyRing.GetKeyPair(cursor) |
||||
return nil |
||||
} |
||||
|
||||
func (k *KeyManager) SetCursor(cursor int) error { |
||||
if cursor >= k.keyRing.Len() { |
||||
return cursorError(cursor, k.keyRing.Len()) |
||||
} |
||||
k.keyPair = k.keyRing.GetKeyPair(cursor) |
||||
return nil |
||||
} |
||||
|
||||
func (k *KeyManager) Init(session string, cursor int, force bool) error { |
||||
var keyRing *KeyRing |
||||
if !force { |
||||
var err error |
||||
keyRing, err = k.load(session) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
} |
||||
if keyRing == nil { |
||||
keyRing = NewGeneratedKeyRing(1) |
||||
} |
||||
return k.reset(session, cursor, keyRing) |
||||
} |
||||
|
||||
func (k *KeyManager) InitFromSecretsFile(session string, cursor int, secretsfile string) error { |
||||
keyRing, err := NewKeyRingFromFile(secretsfile) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
return k.reset(session, cursor, keyRing) |
||||
} |
||||
|
||||
func (k *KeyManager) InitFromString(session string, cursor int, secrets string) error { |
||||
keyRing, err := NewKeyRingFromString(secrets) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
return k.reset(session, cursor, keyRing) |
||||
} |
||||
|
||||
func (k *KeyManager) Export(dir string) error { |
||||
fileKeyStore := FileKeyStore{dir} |
||||
return fileKeyStore.Save(k.session, k.keyRing) |
||||
} |
@ -0,0 +1,112 @@ |
||||
package ethcrypto |
||||
|
||||
import ( |
||||
"fmt" |
||||
"github.com/ethereum/eth-go/ethutil" |
||||
"io/ioutil" |
||||
"os" |
||||
"path" |
||||
"strings" |
||||
) |
||||
|
||||
type KeyStore interface { |
||||
Load(string) (*KeyRing, error) |
||||
Save(string, *KeyRing) error |
||||
} |
||||
|
||||
type DBKeyStore struct { |
||||
db ethutil.Database |
||||
} |
||||
|
||||
const dbKeyPrefix = "KeyRing" |
||||
|
||||
func (k *DBKeyStore) dbKey(session string) []byte { |
||||
return []byte(fmt.Sprintf("%s%s", dbKeyPrefix, session)) |
||||
} |
||||
|
||||
func (k *DBKeyStore) Save(session string, keyRing *KeyRing) error { |
||||
k.db.Put(k.dbKey(session), keyRing.RlpEncode()) |
||||
return nil |
||||
} |
||||
|
||||
func (k *DBKeyStore) Load(session string) (*KeyRing, error) { |
||||
data, err := k.db.Get(k.dbKey(session)) |
||||
if err != nil { |
||||
return nil, nil |
||||
} |
||||
var keyRing *KeyRing |
||||
keyRing, err = NewKeyRingFromBytes(data) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
// if empty keyRing is found we return nil, no error
|
||||
if keyRing.Len() == 0 { |
||||
return nil, nil |
||||
} |
||||
return keyRing, nil |
||||
} |
||||
|
||||
type FileKeyStore struct { |
||||
basedir string |
||||
} |
||||
|
||||
func (k *FileKeyStore) Save(session string, keyRing *KeyRing) error { |
||||
var content []byte |
||||
var err error |
||||
var privateKeys []string |
||||
var publicKeys []string |
||||
var mnemonics []string |
||||
var addresses []string |
||||
keyRing.Each(func(keyPair *KeyPair) { |
||||
privateKeys = append(privateKeys, ethutil.Bytes2Hex(keyPair.PrivateKey)) |
||||
publicKeys = append(publicKeys, ethutil.Bytes2Hex(keyPair.PublicKey)) |
||||
addresses = append(addresses, ethutil.Bytes2Hex(keyPair.Address())) |
||||
mnemonics = append(mnemonics, keyPair.Mnemonic()) |
||||
}) |
||||
|
||||
basename := session |
||||
if session == "" { |
||||
basename = "default" |
||||
} |
||||
|
||||
path := path.Join(k.basedir, basename) |
||||
content = []byte(strings.Join(privateKeys, "\n")) |
||||
err = ioutil.WriteFile(path+".prv", content, 0600) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
content = []byte(strings.Join(publicKeys, "\n")) |
||||
err = ioutil.WriteFile(path+".pub", content, 0644) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
content = []byte(strings.Join(addresses, "\n")) |
||||
err = ioutil.WriteFile(path+".addr", content, 0644) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
content = []byte(strings.Join(mnemonics, "\n")) |
||||
err = ioutil.WriteFile(path+".mne", content, 0600) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func (k *FileKeyStore) Load(session string) (*KeyRing, error) { |
||||
basename := session |
||||
if session == "" { |
||||
basename = "default" |
||||
} |
||||
secfile := path.Join(k.basedir, basename+".prv") |
||||
_, err := os.Stat(secfile) |
||||
// if file is not found then we return nil, no error
|
||||
if err != nil { |
||||
return nil, nil |
||||
} |
||||
return NewKeyRingFromFile(secfile) |
||||
} |
@ -0,0 +1,57 @@ |
||||
package ethcrypto |
||||
|
||||
import ( |
||||
"github.com/ethereum/eth-go/ethutil" |
||||
"github.com/obscuren/secp256k1-go" |
||||
"strings" |
||||
) |
||||
|
||||
type KeyPair struct { |
||||
PrivateKey []byte |
||||
PublicKey []byte |
||||
address []byte |
||||
mnemonic string |
||||
// The associated account
|
||||
// account *StateObject
|
||||
} |
||||
|
||||
func GenerateNewKeyPair() *KeyPair { |
||||
_, prv := secp256k1.GenerateKeyPair() |
||||
keyPair, _ := NewKeyPairFromSec(prv) // swallow error, this one cannot err
|
||||
return keyPair |
||||
} |
||||
|
||||
func NewKeyPairFromSec(seckey []byte) (*KeyPair, error) { |
||||
pubkey, err := secp256k1.GeneratePubKey(seckey) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return &KeyPair{PrivateKey: seckey, PublicKey: pubkey}, nil |
||||
} |
||||
|
||||
func (k *KeyPair) Address() []byte { |
||||
if k.address == nil { |
||||
k.address = Sha3Bin(k.PublicKey[1:])[12:] |
||||
} |
||||
return k.address |
||||
} |
||||
|
||||
func (k *KeyPair) Mnemonic() string { |
||||
if k.mnemonic == "" { |
||||
k.mnemonic = strings.Join(MnemonicEncode(ethutil.Bytes2Hex(k.PrivateKey)), " ") |
||||
} |
||||
return k.mnemonic |
||||
} |
||||
|
||||
func (k *KeyPair) AsStrings() (string, string, string, string) { |
||||
return k.Mnemonic(), ethutil.Bytes2Hex(k.Address()), ethutil.Bytes2Hex(k.PrivateKey), ethutil.Bytes2Hex(k.PublicKey) |
||||
} |
||||
|
||||
func (k *KeyPair) RlpEncode() []byte { |
||||
return k.RlpValue().Encode() |
||||
} |
||||
|
||||
func (k *KeyPair) RlpValue() *ethutil.Value { |
||||
return ethutil.NewValue(k.PrivateKey) |
||||
} |
@ -0,0 +1,118 @@ |
||||
package ethcrypto |
||||
|
||||
import ( |
||||
"fmt" |
||||
"github.com/ethereum/eth-go/ethutil" |
||||
"io/ioutil" |
||||
"strings" |
||||
) |
||||
|
||||
type KeyRing struct { |
||||
keys []*KeyPair |
||||
} |
||||
|
||||
func NewKeyRing() *KeyRing { |
||||
return &KeyRing{} |
||||
} |
||||
|
||||
func (k *KeyRing) AddKeyPair(keyPair *KeyPair) { |
||||
k.keys = append(k.keys, keyPair) |
||||
} |
||||
|
||||
func (k *KeyRing) GetKeyPair(i int) *KeyPair { |
||||
if len(k.keys) > i { |
||||
return k.keys[i] |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func (k *KeyRing) Empty() bool { |
||||
return k.Len() == 0 |
||||
} |
||||
|
||||
func (k *KeyRing) Len() int { |
||||
return len(k.keys) |
||||
} |
||||
|
||||
func (k *KeyRing) Each(f func(*KeyPair)) { |
||||
for _, keyPair := range k.keys { |
||||
f(keyPair) |
||||
} |
||||
} |
||||
|
||||
func NewGeneratedKeyRing(len int) *KeyRing { |
||||
keyRing := NewKeyRing() |
||||
for i := 0; i < len; i++ { |
||||
keyRing.AddKeyPair(GenerateNewKeyPair()) |
||||
} |
||||
return keyRing |
||||
} |
||||
|
||||
func NewKeyRingFromFile(secfile string) (*KeyRing, error) { |
||||
var content []byte |
||||
var err error |
||||
content, err = ioutil.ReadFile(secfile) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
keyRing, err := NewKeyRingFromString(string(content)) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return keyRing, nil |
||||
} |
||||
|
||||
func NewKeyRingFromString(content string) (*KeyRing, error) { |
||||
secretStrings := strings.Split(content, "\n") |
||||
var secrets [][]byte |
||||
for _, secretString := range secretStrings { |
||||
secret := secretString |
||||
words := strings.Split(secretString, " ") |
||||
if len(words) == 24 { |
||||
secret = MnemonicDecode(words) |
||||
} else if len(words) != 1 { |
||||
return nil, fmt.Errorf("Unrecognised key format") |
||||
} |
||||
secrets = append(secrets, ethutil.Hex2Bytes(secret)) |
||||
} |
||||
return NewKeyRingFromSecrets(secrets) |
||||
} |
||||
|
||||
func NewKeyRingFromSecrets(secs [][]byte) (*KeyRing, error) { |
||||
keyRing := NewKeyRing() |
||||
for _, sec := range secs { |
||||
keyPair, err := NewKeyPairFromSec(sec) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
keyRing.AddKeyPair(keyPair) |
||||
} |
||||
return keyRing, nil |
||||
} |
||||
|
||||
func NewKeyRingFromBytes(data []byte) (*KeyRing, error) { |
||||
var secrets [][]byte |
||||
it := ethutil.NewValueFromBytes(data).NewIterator() |
||||
for it.Next() { |
||||
secret := it.Value().Bytes() |
||||
secrets = append(secrets, secret) |
||||
} |
||||
keyRing, err := NewKeyRingFromSecrets(secrets) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return keyRing, nil |
||||
} |
||||
|
||||
func (k *KeyRing) RlpEncode() []byte { |
||||
return k.RlpValue().Encode() |
||||
} |
||||
|
||||
func (k *KeyRing) RlpValue() *ethutil.Value { |
||||
v := ethutil.EmptyValue() |
||||
k.Each(func(keyPair *KeyPair) { |
||||
v.Append(keyPair.RlpValue()) |
||||
}) |
||||
return v |
||||
} |
@ -0,0 +1,122 @@ |
||||
package ethcrypto |
||||
|
||||
import ( |
||||
"github.com/ethereum/eth-go/ethdb" |
||||
// "io/ioutil"
|
||||
"fmt" |
||||
"os" |
||||
"path" |
||||
"testing" |
||||
) |
||||
|
||||
// test if persistence layer works
|
||||
func TestDBKeyManager(t *testing.T) { |
||||
memdb, _ := ethdb.NewMemDatabase() |
||||
keyManager0 := NewDBKeyManager(memdb) |
||||
err := keyManager0.Init("", 0, false) |
||||
if err != nil { |
||||
t.Error("Unexpected error: ", err) |
||||
} |
||||
keyManager1 := NewDBKeyManager(memdb) |
||||
err = keyManager1.Init("", 0, false) |
||||
if err != nil { |
||||
t.Error("Unexpected error: ", err) |
||||
} |
||||
if string(keyManager0.PrivateKey()) != string(keyManager1.PrivateKey()) { |
||||
t.Error("Expected private keys %x, %x, to be identical via db persistence", keyManager0.PrivateKey(), keyManager1.PrivateKey()) |
||||
} |
||||
err = keyManager1.Init("", 0, true) |
||||
if err != nil { |
||||
t.Error("Unexpected error: ", err) |
||||
} |
||||
if string(keyManager0.PrivateKey()) == string(keyManager1.PrivateKey()) { |
||||
t.Error("Expected private keys %x, %x, to be be different despite db persistence if force generate", keyManager0.PrivateKey(), keyManager1.PrivateKey()) |
||||
} |
||||
} |
||||
|
||||
func TestFileKeyManager(t *testing.T) { |
||||
basedir0 := "/tmp/ethtest0" |
||||
os.RemoveAll(basedir0) |
||||
os.Mkdir(basedir0, 0777) |
||||
|
||||
keyManager0 := NewFileKeyManager(basedir0) |
||||
err := keyManager0.Init("", 0, false) |
||||
if err != nil { |
||||
t.Error("Unexpected error: ", err) |
||||
} |
||||
|
||||
keyManager1 := NewFileKeyManager(basedir0) |
||||
|
||||
err = keyManager1.Init("", 0, false) |
||||
if err != nil { |
||||
t.Error("Unexpected error: ", err) |
||||
} |
||||
if string(keyManager0.PrivateKey()) != string(keyManager1.PrivateKey()) { |
||||
t.Error("Expected private keys %x, %x, to be identical via db persistence", keyManager0.PrivateKey(), keyManager1.PrivateKey()) |
||||
} |
||||
|
||||
err = keyManager1.Init("", 0, true) |
||||
if err != nil { |
||||
t.Error("Unexpected error: ", err) |
||||
} |
||||
if string(keyManager0.PrivateKey()) == string(keyManager1.PrivateKey()) { |
||||
t.Error("Expected private keys %x, %x, to be be different despite db persistence if force generate", keyManager0.PrivateKey(), keyManager1.PrivateKey()) |
||||
} |
||||
} |
||||
|
||||
// cursor errors
|
||||
func TestCursorErrors(t *testing.T) { |
||||
memdb, _ := ethdb.NewMemDatabase() |
||||
keyManager0 := NewDBKeyManager(memdb) |
||||
err := keyManager0.Init("", 0, false) |
||||
err = keyManager0.Init("", 1, false) |
||||
if err == nil { |
||||
t.Error("Expected cursor error") |
||||
} |
||||
err = keyManager0.SetCursor(1) |
||||
if err == nil { |
||||
t.Error("Expected cursor error") |
||||
} |
||||
} |
||||
|
||||
func TestExportImport(t *testing.T) { |
||||
memdb, _ := ethdb.NewMemDatabase() |
||||
keyManager0 := NewDBKeyManager(memdb) |
||||
err := keyManager0.Init("", 0, false) |
||||
basedir0 := "/tmp/ethtest0" |
||||
os.RemoveAll(basedir0) |
||||
os.Mkdir(basedir0, 0777) |
||||
keyManager0.Export(basedir0) |
||||
|
||||
keyManager1 := NewFileKeyManager(basedir0) |
||||
err = keyManager1.Init("", 0, false) |
||||
if err != nil { |
||||
t.Error("Unexpected error: ", err) |
||||
} |
||||
fmt.Printf("keyRing: %v\n", keyManager0.KeyPair()) |
||||
fmt.Printf("keyRing: %v\n", keyManager1.KeyPair()) |
||||
if string(keyManager0.PrivateKey()) != string(keyManager1.PrivateKey()) { |
||||
t.Error("Expected private keys %x, %x, to be identical via export to filestore basedir", keyManager0.PrivateKey(), keyManager1.PrivateKey()) |
||||
} |
||||
path.Join("") |
||||
|
||||
// memdb, _ = ethdb.NewMemDatabase()
|
||||
// keyManager2 := NewDBKeyManager(memdb)
|
||||
// err = keyManager2.InitFromSecretsFile("", 0, path.Join(basedir0, "default.prv"))
|
||||
// if err != nil {
|
||||
// t.Error("Unexpected error: ", err)
|
||||
// }
|
||||
// if string(keyManager0.PrivateKey()) != string(keyManager2.PrivateKey()) {
|
||||
// t.Error("Expected private keys %s, %s, to be identical via export/import prv", keyManager0.PrivateKey(), keyManager1.PrivateKey())
|
||||
// }
|
||||
|
||||
// memdb, _ = ethdb.NewMemDatabase()
|
||||
// keyManager3 := NewDBKeyManager(memdb)
|
||||
// err = keyManager3.InitFromSecretsFile("", 0, path.Join(basedir0, "default.mne"))
|
||||
// if err != nil {
|
||||
// t.Error("Unexpected error: ", err)
|
||||
// }
|
||||
// if string(keyManager0.PrivateKey()) != string(keyManager3.PrivateKey()) {
|
||||
// t.Error("Expected private keys %s, %s, to be identical via export/import mnemonic file", keyManager0.PrivateKey(), keyManager1.PrivateKey())
|
||||
// }
|
||||
} |
@ -0,0 +1,76 @@ |
||||
package ethcrypto |
||||
|
||||
import ( |
||||
"fmt" |
||||
"io/ioutil" |
||||
"path" |
||||
"runtime" |
||||
"strconv" |
||||
"strings" |
||||
) |
||||
|
||||
func InitWords() []string { |
||||
_, thisfile, _, _ := runtime.Caller(1) |
||||
filename := path.Join(path.Dir(thisfile), "mnemonic.words.lst") |
||||
content, err := ioutil.ReadFile(filename) |
||||
if err != nil { |
||||
panic(fmt.Errorf("reading mnemonic word list file 'mnemonic.words.lst' failed: ", err)) |
||||
} |
||||
return strings.Split(string(content), "\n") |
||||
} |
||||
|
||||
var words = InitWords() |
||||
|
||||
// TODO: See if we can refactor this into a shared util lib if we need it multiple times
|
||||
func IndexOf(slice []string, value string) int64 { |
||||
for p, v := range slice { |
||||
if v == value { |
||||
return int64(p) |
||||
} |
||||
} |
||||
return -1 |
||||
} |
||||
|
||||
func MnemonicEncode(message string) []string { |
||||
var out []string |
||||
n := int64(len(words)) |
||||
|
||||
for i := 0; i < len(message); i += (len(message) / 8) { |
||||
x := message[i : i+8] |
||||
bit, _ := strconv.ParseInt(x, 16, 64) |
||||
w1 := (bit % n) |
||||
w2 := ((bit / n) + w1) % n |
||||
w3 := ((bit / n / n) + w2) % n |
||||
out = append(out, words[w1], words[w2], words[w3]) |
||||
} |
||||
return out |
||||
} |
||||
|
||||
func MnemonicDecode(wordsar []string) string { |
||||
var out string |
||||
n := int64(len(words)) |
||||
|
||||
for i := 0; i < len(wordsar); i += 3 { |
||||
word1 := wordsar[i] |
||||
word2 := wordsar[i+1] |
||||
word3 := wordsar[i+2] |
||||
w1 := IndexOf(words, word1) |
||||
w2 := IndexOf(words, word2) |
||||
w3 := IndexOf(words, word3) |
||||
|
||||
y := (w2 - w1) % n |
||||
z := (w3 - w2) % n |
||||
|
||||
// Golang handles modulo with negative numbers different then most languages
|
||||
// The modulo can be negative, we don't want that.
|
||||
if z < 0 { |
||||
z += n |
||||
} |
||||
if y < 0 { |
||||
y += n |
||||
} |
||||
x := w1 + n*(y) + n*n*(z) |
||||
out += fmt.Sprintf("%08x", x) |
||||
} |
||||
return out |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@ |
||||
package ethutil |
||||
package ethcrypto |
||||
|
||||
import ( |
||||
"testing" |
@ -1,4 +1,4 @@ |
||||
package ethutil |
||||
package ethtrie |
||||
|
||||
import ( |
||||
"bytes" |
@ -1,4 +1,4 @@ |
||||
package ethutil |
||||
package ethtrie |
||||
|
||||
import ( |
||||
"fmt" |
@ -0,0 +1,26 @@ |
||||
package ethtrie |
||||
|
||||
import () |
||||
|
||||
// Helper function for comparing slices
|
||||
func CompareIntSlice(a, b []int) bool { |
||||
if len(a) != len(b) { |
||||
return false |
||||
} |
||||
for i, v := range a { |
||||
if v != b[i] { |
||||
return false |
||||
} |
||||
} |
||||
return true |
||||
} |
||||
|
||||
// Returns the amount of nibbles that match each other from 0 ...
|
||||
func MatchingNibbleLength(a, b []int) int { |
||||
i := 0 |
||||
for CompareIntSlice(a[:i+1], b[:i+1]) && i < len(b) { |
||||
i += 1 |
||||
} |
||||
|
||||
return i |
||||
} |
@ -1,4 +1,4 @@ |
||||
package ethutil |
||||
package ethtrie |
||||
|
||||
import ( |
||||
"bytes" |
@ -1,64 +0,0 @@ |
||||
package ethutil |
||||
|
||||
import ( |
||||
"code.google.com/p/go.crypto/ripemd160" |
||||
"crypto/sha256" |
||||
"encoding/hex" |
||||
"github.com/obscuren/sha3" |
||||
"strconv" |
||||
) |
||||
|
||||
func Uitoa(i uint32) string { |
||||
return strconv.FormatUint(uint64(i), 10) |
||||
} |
||||
|
||||
func Sha256Bin(data []byte) []byte { |
||||
hash := sha256.Sum256(data) |
||||
|
||||
return hash[:] |
||||
} |
||||
|
||||
func Ripemd160(data []byte) []byte { |
||||
ripemd := ripemd160.New() |
||||
ripemd.Write(data) |
||||
|
||||
return ripemd.Sum(nil) |
||||
} |
||||
|
||||
func Sha3Bin(data []byte) []byte { |
||||
d := sha3.NewKeccak256() |
||||
d.Write(data) |
||||
|
||||
return d.Sum(nil) |
||||
} |
||||
|
||||
// Helper function for comparing slices
|
||||
func CompareIntSlice(a, b []int) bool { |
||||
if len(a) != len(b) { |
||||
return false |
||||
} |
||||
for i, v := range a { |
||||
if v != b[i] { |
||||
return false |
||||
} |
||||
} |
||||
return true |
||||
} |
||||
|
||||
// Returns the amount of nibbles that match each other from 0 ...
|
||||
func MatchingNibbleLength(a, b []int) int { |
||||
i := 0 |
||||
for CompareIntSlice(a[:i+1], b[:i+1]) && i < len(b) { |
||||
i += 1 |
||||
} |
||||
|
||||
return i |
||||
} |
||||
|
||||
func Hex(d []byte) string { |
||||
return hex.EncodeToString(d) |
||||
} |
||||
func FromHex(str string) []byte { |
||||
h, _ := hex.DecodeString(str) |
||||
return h |
||||
} |
@ -1,115 +0,0 @@ |
||||
package ethutil |
||||
|
||||
import ( |
||||
"github.com/obscuren/secp256k1-go" |
||||
) |
||||
|
||||
type KeyPair struct { |
||||
PrivateKey []byte |
||||
PublicKey []byte |
||||
|
||||
// The associated account
|
||||
account *StateObject |
||||
} |
||||
|
||||
func GenerateNewKeyPair() (*KeyPair, error) { |
||||
_, prv := secp256k1.GenerateKeyPair() |
||||
|
||||
return NewKeyPairFromSec(prv) |
||||
} |
||||
|
||||
func NewKeyPairFromSec(seckey []byte) (*KeyPair, error) { |
||||
pubkey, err := secp256k1.GeneratePubKey(seckey) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return &KeyPair{PrivateKey: seckey, PublicKey: pubkey}, nil |
||||
} |
||||
|
||||
func NewKeyPairFromValue(val *Value) *KeyPair { |
||||
v, _ := NewKeyPairFromSec(val.Bytes()) |
||||
|
||||
return v |
||||
} |
||||
|
||||
func (k *KeyPair) Address() []byte { |
||||
return Sha3Bin(k.PublicKey[1:])[12:] |
||||
} |
||||
|
||||
func (k *KeyPair) RlpEncode() []byte { |
||||
return k.RlpValue().Encode() |
||||
} |
||||
|
||||
func (k *KeyPair) RlpValue() *Value { |
||||
return NewValue(k.PrivateKey) |
||||
} |
||||
|
||||
type KeyRing struct { |
||||
keys []*KeyPair |
||||
} |
||||
|
||||
func (k *KeyRing) Add(pair *KeyPair) { |
||||
k.keys = append(k.keys, pair) |
||||
} |
||||
|
||||
func (k *KeyRing) Get(i int) *KeyPair { |
||||
if len(k.keys) > i { |
||||
return k.keys[i] |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func (k *KeyRing) Len() int { |
||||
return len(k.keys) |
||||
} |
||||
|
||||
func (k *KeyRing) NewKeyPair(sec []byte) (*KeyPair, error) { |
||||
keyPair, err := NewKeyPairFromSec(sec) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
k.Add(keyPair) |
||||
Config.Db.Put([]byte("KeyRing"), k.RlpValue().Encode()) |
||||
|
||||
return keyPair, nil |
||||
} |
||||
|
||||
func (k *KeyRing) Reset() { |
||||
Config.Db.Put([]byte("KeyRing"), nil) |
||||
k.keys = nil |
||||
} |
||||
|
||||
func (k *KeyRing) RlpValue() *Value { |
||||
v := EmptyValue() |
||||
for _, keyPair := range k.keys { |
||||
v.Append(keyPair.RlpValue()) |
||||
} |
||||
|
||||
return v |
||||
} |
||||
|
||||
// The public "singleton" keyring
|
||||
var keyRing *KeyRing |
||||
|
||||
func GetKeyRing() *KeyRing { |
||||
if keyRing == nil { |
||||
keyRing = &KeyRing{} |
||||
|
||||
data, _ := Config.Db.Get([]byte("KeyRing")) |
||||
it := NewValueFromBytes(data).NewIterator() |
||||
for it.Next() { |
||||
v := it.Value() |
||||
|
||||
key, err := NewKeyPairFromSec(v.Bytes()) |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
keyRing.Add(key) |
||||
} |
||||
} |
||||
|
||||
return keyRing |
||||
} |
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue