diff --git a/account/account.go b/account/account.go new file mode 100644 index 0000000000000000000000000000000000000000..9a0121ebc122d794379aae6b1c96b8052a2f3a32 --- /dev/null +++ b/account/account.go @@ -0,0 +1,110 @@ +// Copyright 2015, 2016 Eris Industries (UK) Ltd. +// This file is part of Eris-RT + +// Eris-RT is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Eris-RT is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Eris-RT. If not, see <http://www.gnu.org/licenses/>. + +// TODO: [ben] Account and PrivateAccount need to become a pure interface +// and then move the implementation to the manager types. +// Eg, Geth has its accounts, different from ErisMint + +package account + +import ( + "bytes" + "fmt" + "io" + + ptypes "github.com/eris-ltd/eris-db/permission/types" + . "github.com/tendermint/go-common" + "github.com/tendermint/go-crypto" + "github.com/tendermint/go-merkle" + "github.com/tendermint/go-wire" +) + +// Signable is an interface for all signable things. +// It typically removes signatures before serializing. +type Signable interface { + WriteSignBytes(chainID string, w io.Writer, n *int, err *error) +} + +// SignBytes is a convenience method for getting the bytes to sign of a Signable. +func SignBytes(chainID string, o Signable) []byte { + buf, n, err := new(bytes.Buffer), new(int), new(error) + o.WriteSignBytes(chainID, buf, n, err) + if *err != nil { + PanicCrisis(err) + } + return buf.Bytes() +} + +// HashSignBytes is a convenience method for getting the hash of the bytes of a signable +func HashSignBytes(chainID string, o Signable) []byte { + return merkle.SimpleHashFromBinary(SignBytes(chainID, o)) +} + +//----------------------------------------------------------------------------- + +// Account resides in the application state, and is mutated by transactions +// on the blockchain. +// Serialized by wire.[read|write]Reflect +type Account struct { + Address []byte `json:"address"` + PubKey crypto.PubKey `json:"pub_key"` + Sequence int `json:"sequence"` + Balance int64 `json:"balance"` + Code []byte `json:"code"` // VM code + StorageRoot []byte `json:"storage_root"` // VM storage merkle root. + + Permissions ptypes.AccountPermissions `json:"permissions"` +} + +func (acc *Account) Copy() *Account { + accCopy := *acc + return &accCopy +} + +func (acc *Account) String() string { + if acc == nil { + return "nil-Account" + } + return fmt.Sprintf("Account{%X:%v B:%v C:%v S:%X P:%s}", acc.Address, acc.PubKey, acc.Balance, len(acc.Code), acc.StorageRoot, acc.Permissions) +} + +func AccountEncoder(o interface{}, w io.Writer, n *int, err *error) { + wire.WriteBinary(o.(*Account), w, n, err) +} + +func AccountDecoder(r io.Reader, n *int, err *error) interface{} { + return wire.ReadBinary(&Account{}, r, 0, n, err) +} + +var AccountCodec = wire.Codec{ + Encode: AccountEncoder, + Decode: AccountDecoder, +} + +func EncodeAccount(acc *Account) []byte { + w := new(bytes.Buffer) + var n int + var err error + AccountEncoder(acc, w, &n, &err) + return w.Bytes() +} + +func DecodeAccount(accBytes []byte) *Account { + var n int + var err error + acc := AccountDecoder(bytes.NewBuffer(accBytes), &n, &err) + return acc.(*Account) +} diff --git a/account/priv_account.go b/account/priv_account.go new file mode 100644 index 0000000000000000000000000000000000000000..52c0ab7710f40bb5708bb5b1cd4a44f413d76d58 --- /dev/null +++ b/account/priv_account.go @@ -0,0 +1,105 @@ +// Copyright 2015, 2016 Eris Industries (UK) Ltd. +// This file is part of Eris-RT + +// Eris-RT is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Eris-RT is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Eris-RT. If not, see <http://www.gnu.org/licenses/>. + +// TODO: [ben] Account and PrivateAccount need to become a pure interface +// and then move the implementation to the manager types. +// Eg, Geth has its accounts, different from ErisMint + +package account + +import ( + "github.com/tendermint/ed25519" + . "github.com/tendermint/go-common" + "github.com/tendermint/go-crypto" + "github.com/tendermint/go-wire" +) + +type PrivAccount struct { + Address []byte `json:"address"` + PubKey crypto.PubKey `json:"pub_key"` + PrivKey crypto.PrivKey `json:"priv_key"` +} + +func (pA *PrivAccount) Generate(index int) *PrivAccount { + newPrivKey := pA.PrivKey.(crypto.PrivKeyEd25519).Generate(index) + newPubKey := newPrivKey.PubKey() + newAddress := newPubKey.Address() + return &PrivAccount{ + Address: newAddress, + PubKey: newPubKey, + PrivKey: newPrivKey, + } +} + +func (pA *PrivAccount) Sign(chainID string, o Signable) crypto.Signature { + return pA.PrivKey.Sign(SignBytes(chainID, o)) +} + +func (pA *PrivAccount) String() string { + return Fmt("PrivAccount{%X}", pA.Address) +} + +//---------------------------------------- + +// Generates a new account with private key. +func GenPrivAccount() *PrivAccount { + privKeyBytes := new([64]byte) + copy(privKeyBytes[:32], crypto.CRandBytes(32)) + pubKeyBytes := ed25519.MakePublicKey(privKeyBytes) + pubKey := crypto.PubKeyEd25519(*pubKeyBytes) + privKey := crypto.PrivKeyEd25519(*privKeyBytes) + return &PrivAccount{ + Address: pubKey.Address(), + PubKey: pubKey, + PrivKey: privKey, + } +} + +// Generates 32 priv key bytes from secret +func GenPrivKeyBytesFromSecret(secret string) []byte { + return wire.BinarySha256(secret) // Not Ripemd160 because we want 32 bytes. +} + +// Generates a new account with private key from SHA256 hash of a secret +func GenPrivAccountFromSecret(secret string) *PrivAccount { + privKey32 := GenPrivKeyBytesFromSecret(secret) + privKeyBytes := new([64]byte) + copy(privKeyBytes[:32], privKey32) + pubKeyBytes := ed25519.MakePublicKey(privKeyBytes) + pubKey := crypto.PubKeyEd25519(*pubKeyBytes) + privKey := crypto.PrivKeyEd25519(*privKeyBytes) + return &PrivAccount{ + Address: pubKey.Address(), + PubKey: pubKey, + PrivKey: privKey, + } +} + +func GenPrivAccountFromPrivKeyBytes(privKeyBytes []byte) *PrivAccount { + if len(privKeyBytes) != 64 { + PanicSanity(Fmt("Expected 64 bytes but got %v", len(privKeyBytes))) + } + var privKeyArray [64]byte + copy(privKeyArray[:], privKeyBytes) + pubKeyBytes := ed25519.MakePublicKey(&privKeyArray) + pubKey := crypto.PubKeyEd25519(*pubKeyBytes) + privKey := crypto.PrivKeyEd25519(privKeyArray) + return &PrivAccount{ + Address: pubKey.Address(), + PubKey: pubKey, + PrivKey: privKey, + } +}