github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/mobile/accounts.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // Copyright 2019 The go-aigar Authors 3 // This file is part of the go-aigar library. 4 // 5 // The go-aigar library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-aigar library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>. 17 18 // Contains all the wrappers from the accounts package to support client side key 19 // management on mobile platforms. 20 21 package geth 22 23 import ( 24 "errors" 25 "time" 26 27 "github.com/AigarNetwork/aigar/accounts" 28 "github.com/AigarNetwork/aigar/accounts/keystore" 29 "github.com/AigarNetwork/aigar/common" 30 "github.com/AigarNetwork/aigar/crypto" 31 ) 32 33 const ( 34 // StandardScryptN is the N parameter of Scrypt encryption algorithm, using 256MB 35 // memory and taking approximately 1s CPU time on a modern processor. 36 StandardScryptN = int(keystore.StandardScryptN) 37 38 // StandardScryptP is the P parameter of Scrypt encryption algorithm, using 256MB 39 // memory and taking approximately 1s CPU time on a modern processor. 40 StandardScryptP = int(keystore.StandardScryptP) 41 42 // LightScryptN is the N parameter of Scrypt encryption algorithm, using 4MB 43 // memory and taking approximately 100ms CPU time on a modern processor. 44 LightScryptN = int(keystore.LightScryptN) 45 46 // LightScryptP is the P parameter of Scrypt encryption algorithm, using 4MB 47 // memory and taking approximately 100ms CPU time on a modern processor. 48 LightScryptP = int(keystore.LightScryptP) 49 ) 50 51 // Account represents a stored key. 52 type Account struct{ account accounts.Account } 53 54 // Accounts represents a slice of accounts. 55 type Accounts struct{ accounts []accounts.Account } 56 57 // Size returns the number of accounts in the slice. 58 func (a *Accounts) Size() int { 59 return len(a.accounts) 60 } 61 62 // Get returns the account at the given index from the slice. 63 func (a *Accounts) Get(index int) (account *Account, _ error) { 64 if index < 0 || index >= len(a.accounts) { 65 return nil, errors.New("index out of bounds") 66 } 67 return &Account{a.accounts[index]}, nil 68 } 69 70 // Set sets the account at the given index in the slice. 71 func (a *Accounts) Set(index int, account *Account) error { 72 if index < 0 || index >= len(a.accounts) { 73 return errors.New("index out of bounds") 74 } 75 a.accounts[index] = account.account 76 return nil 77 } 78 79 // GetAddress retrieves the address associated with the account. 80 func (a *Account) GetAddress() *Address { 81 return &Address{a.account.Address} 82 } 83 84 // GetURL retrieves the canonical URL of the account. 85 func (a *Account) GetURL() string { 86 return a.account.URL.String() 87 } 88 89 // KeyStore manages a key storage directory on disk. 90 type KeyStore struct{ keystore *keystore.KeyStore } 91 92 // NewKeyStore creates a keystore for the given directory. 93 func NewKeyStore(keydir string, scryptN, scryptP int) *KeyStore { 94 return &KeyStore{keystore: keystore.NewKeyStore(keydir, scryptN, scryptP)} 95 } 96 97 // HasAddress reports whether a key with the given address is present. 98 func (ks *KeyStore) HasAddress(address *Address) bool { 99 return ks.keystore.HasAddress(address.address) 100 } 101 102 // GetAccounts returns all key files present in the directory. 103 func (ks *KeyStore) GetAccounts() *Accounts { 104 return &Accounts{ks.keystore.Accounts()} 105 } 106 107 // DeleteAccount deletes the key matched by account if the passphrase is correct. 108 // If a contains no filename, the address must match a unique key. 109 func (ks *KeyStore) DeleteAccount(account *Account, passphrase string) error { 110 return ks.keystore.Delete(account.account, passphrase) 111 } 112 113 // SignHash calculates a ECDSA signature for the given hash. The produced signature 114 // is in the [R || S || V] format where V is 0 or 1. 115 func (ks *KeyStore) SignHash(address *Address, hash []byte) (signature []byte, _ error) { 116 return ks.keystore.SignHash(accounts.Account{Address: address.address}, common.CopyBytes(hash)) 117 } 118 119 // SignTx signs the given transaction with the requested account. 120 func (ks *KeyStore) SignTx(account *Account, tx *Transaction, chainID *BigInt) (*Transaction, error) { 121 if chainID == nil { // Null passed from mobile app 122 chainID = new(BigInt) 123 } 124 signed, err := ks.keystore.SignTx(account.account, tx.tx, chainID.bigint) 125 if err != nil { 126 return nil, err 127 } 128 return &Transaction{signed}, nil 129 } 130 131 // SignHashPassphrase signs hash if the private key matching the given address can 132 // be decrypted with the given passphrase. The produced signature is in the 133 // [R || S || V] format where V is 0 or 1. 134 func (ks *KeyStore) SignHashPassphrase(account *Account, passphrase string, hash []byte) (signature []byte, _ error) { 135 return ks.keystore.SignHashWithPassphrase(account.account, passphrase, common.CopyBytes(hash)) 136 } 137 138 // SignTxPassphrase signs the transaction if the private key matching the 139 // given address can be decrypted with the given passphrase. 140 func (ks *KeyStore) SignTxPassphrase(account *Account, passphrase string, tx *Transaction, chainID *BigInt) (*Transaction, error) { 141 if chainID == nil { // Null passed from mobile app 142 chainID = new(BigInt) 143 } 144 signed, err := ks.keystore.SignTxWithPassphrase(account.account, passphrase, tx.tx, chainID.bigint) 145 if err != nil { 146 return nil, err 147 } 148 return &Transaction{signed}, nil 149 } 150 151 // Unlock unlocks the given account indefinitely. 152 func (ks *KeyStore) Unlock(account *Account, passphrase string) error { 153 return ks.keystore.TimedUnlock(account.account, passphrase, 0) 154 } 155 156 // Lock removes the private key with the given address from memory. 157 func (ks *KeyStore) Lock(address *Address) error { 158 return ks.keystore.Lock(address.address) 159 } 160 161 // TimedUnlock unlocks the given account with the passphrase. The account stays 162 // unlocked for the duration of timeout (nanoseconds). A timeout of 0 unlocks the 163 // account until the program exits. The account must match a unique key file. 164 // 165 // If the account address is already unlocked for a duration, TimedUnlock extends or 166 // shortens the active unlock timeout. If the address was previously unlocked 167 // indefinitely the timeout is not altered. 168 func (ks *KeyStore) TimedUnlock(account *Account, passphrase string, timeout int64) error { 169 return ks.keystore.TimedUnlock(account.account, passphrase, time.Duration(timeout)) 170 } 171 172 // NewAccount generates a new key and stores it into the key directory, 173 // encrypting it with the passphrase. 174 func (ks *KeyStore) NewAccount(passphrase string) (*Account, error) { 175 account, err := ks.keystore.NewAccount(passphrase) 176 if err != nil { 177 return nil, err 178 } 179 return &Account{account}, nil 180 } 181 182 // UpdateAccount changes the passphrase of an existing account. 183 func (ks *KeyStore) UpdateAccount(account *Account, passphrase, newPassphrase string) error { 184 return ks.keystore.Update(account.account, passphrase, newPassphrase) 185 } 186 187 // ExportKey exports as a JSON key, encrypted with newPassphrase. 188 func (ks *KeyStore) ExportKey(account *Account, passphrase, newPassphrase string) (key []byte, _ error) { 189 return ks.keystore.Export(account.account, passphrase, newPassphrase) 190 } 191 192 // ImportKey stores the given encrypted JSON key into the key directory. 193 func (ks *KeyStore) ImportKey(keyJSON []byte, passphrase, newPassphrase string) (account *Account, _ error) { 194 acc, err := ks.keystore.Import(common.CopyBytes(keyJSON), passphrase, newPassphrase) 195 if err != nil { 196 return nil, err 197 } 198 return &Account{acc}, nil 199 } 200 201 // ImportECDSAKey stores the given encrypted JSON key into the key directory. 202 func (ks *KeyStore) ImportECDSAKey(key []byte, passphrase string) (account *Account, _ error) { 203 privkey, err := crypto.ToECDSA(common.CopyBytes(key)) 204 if err != nil { 205 return nil, err 206 } 207 acc, err := ks.keystore.ImportECDSA(privkey, passphrase) 208 if err != nil { 209 return nil, err 210 } 211 return &Account{acc}, nil 212 } 213 214 // ImportPreSaleKey decrypts the given Ethereum presale wallet and stores 215 // a key file in the key directory. The key file is encrypted with the same passphrase. 216 func (ks *KeyStore) ImportPreSaleKey(keyJSON []byte, passphrase string) (ccount *Account, _ error) { 217 account, err := ks.keystore.ImportPreSaleKey(common.CopyBytes(keyJSON), passphrase) 218 if err != nil { 219 return nil, err 220 } 221 return &Account{account}, nil 222 }