mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-23 21:26:42 +00:00
crypto, common, xeth: implemented checksum addresses
This commit is contained in:
parent
cd81356ace
commit
b9e93b69a7
6 changed files with 138 additions and 19 deletions
|
|
@ -117,6 +117,33 @@ func (a *Address) Set(other Address) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ChecksumAddress is an address with an included checksum. A checksum address
|
||||||
|
// is usually made out of SHA3(A) + A
|
||||||
|
type ChecksumAddress struct {
|
||||||
|
Checksum [4]byte
|
||||||
|
Address
|
||||||
|
}
|
||||||
|
|
||||||
|
// HexToChecksumAddress converts a hex checksum address to a ChecksumAddress
|
||||||
|
// type
|
||||||
|
func HexToChecksumAddress(s string) ChecksumAddress {
|
||||||
|
if len(s) > 2 && s[:2] == "0x" {
|
||||||
|
s = s[2:]
|
||||||
|
}
|
||||||
|
if len(s) != 48 {
|
||||||
|
return ChecksumAddress{}
|
||||||
|
}
|
||||||
|
|
||||||
|
addr := ChecksumAddress{[4]byte{}, HexToAddress(s[4:])}
|
||||||
|
copy(addr.Checksum[:], Hex2Bytes(s[:8]))
|
||||||
|
return addr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hex returns the hexadecimal representation of a checksum address
|
||||||
|
func (ca ChecksumAddress) Hex() string {
|
||||||
|
return "0x" + Bytes2Hex(ca.Checksum[:]) + ca.Address.Hex()[2:]
|
||||||
|
}
|
||||||
|
|
||||||
// PP Pretty Prints a byte slice in the following format:
|
// PP Pretty Prints a byte slice in the following format:
|
||||||
// hex(value[:4])...(hex[len(value)-4:])
|
// hex(value[:4])...(hex[len(value)-4:])
|
||||||
func PP(value []byte) string {
|
func PP(value []byte) string {
|
||||||
|
|
|
||||||
44
crypto/address.go
Normal file
44
crypto/address.go
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
package crypto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
)
|
||||||
|
|
||||||
|
const checksumLen = 4
|
||||||
|
|
||||||
|
// Creates an ethereum address given the bytes and the nonce
|
||||||
|
func CreateAddress(b common.Address, nonce uint64) common.Address {
|
||||||
|
data, _ := rlp.EncodeToBytes([]interface{}{b, nonce})
|
||||||
|
return common.BytesToAddress(Sha3(data)[12:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChecksumAddress creates modifies an address to include a checksum
|
||||||
|
func ChecksumAddress(addr common.Address) common.ChecksumAddress {
|
||||||
|
var checksumaddr common.ChecksumAddress
|
||||||
|
checksumaddr.Address = addr
|
||||||
|
copy(checksumaddr.Checksum[:], Sha3(addr.Bytes())[:4])
|
||||||
|
|
||||||
|
return checksumaddr
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateAddress validates the given address. It must include a checksum
|
||||||
|
// on the end. It returns the address or an error if the checksum or length of
|
||||||
|
// the input failed.
|
||||||
|
func ValidateAddress(addr common.ChecksumAddress) (common.Address, error) {
|
||||||
|
if !bytes.Equal(Sha3(addr.Address[:])[:4], addr.Checksum[:]) {
|
||||||
|
return common.Address{}, fmt.Errorf("checksum failed for address %x (%x)", addr.Address, addr.Checksum)
|
||||||
|
}
|
||||||
|
|
||||||
|
return addr.Address, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PubkeyToAddress converts a std ecdsa public key to a common.Address
|
||||||
|
func PubkeyToAddress(p ecdsa.PublicKey) common.Address {
|
||||||
|
pubBytes := FromECDSAPub(&p)
|
||||||
|
return common.BytesToAddress(Sha3(pubBytes[1:])[12:])
|
||||||
|
}
|
||||||
33
crypto/address_test.go
Normal file
33
crypto/address_test.go
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
package crypto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestChecksum(t *testing.T) {
|
||||||
|
var addr common.Address
|
||||||
|
addr[0] = 1
|
||||||
|
|
||||||
|
checksumed := ChecksumAddress(addr)
|
||||||
|
if !bytes.Equal(checksumed.Checksum[:], Sha3(checksumed.Address[:])[:4]) {
|
||||||
|
t.Error("checksum failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, err := ValidateAddress(checksumed)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if addr != addr {
|
||||||
|
t.Error("address failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
checksumed.Checksum[3] |= 1
|
||||||
|
_, err = ValidateAddress(checksumed)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("checksum success, should have failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -38,7 +38,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/crypto/ecies"
|
"github.com/ethereum/go-ethereum/crypto/ecies"
|
||||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||||
"github.com/ethereum/go-ethereum/crypto/sha3"
|
"github.com/ethereum/go-ethereum/crypto/sha3"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
|
||||||
"golang.org/x/crypto/pbkdf2"
|
"golang.org/x/crypto/pbkdf2"
|
||||||
"golang.org/x/crypto/ripemd160"
|
"golang.org/x/crypto/ripemd160"
|
||||||
)
|
)
|
||||||
|
|
@ -68,13 +67,6 @@ func Sha3Hash(data ...[]byte) (h common.Hash) {
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates an ethereum address given the bytes and the nonce
|
|
||||||
func CreateAddress(b common.Address, nonce uint64) common.Address {
|
|
||||||
data, _ := rlp.EncodeToBytes([]interface{}{b, nonce})
|
|
||||||
return common.BytesToAddress(Sha3(data)[12:])
|
|
||||||
//return Sha3(common.NewValue([]interface{}{b, nonce}).Encode())[12:]
|
|
||||||
}
|
|
||||||
|
|
||||||
func Sha256(data []byte) []byte {
|
func Sha256(data []byte) []byte {
|
||||||
hash := sha256.Sum256(data)
|
hash := sha256.Sum256(data)
|
||||||
|
|
||||||
|
|
@ -332,8 +324,3 @@ func PKCS7Unpad(in []byte) []byte {
|
||||||
}
|
}
|
||||||
return in[:len(in)-int(padding)]
|
return in[:len(in)-int(padding)]
|
||||||
}
|
}
|
||||||
|
|
||||||
func PubkeyToAddress(p ecdsa.PublicKey) common.Address {
|
|
||||||
pubBytes := FromECDSAPub(&p)
|
|
||||||
return common.BytesToAddress(Sha3(pubBytes[1:])[12:])
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -2256,6 +2256,17 @@ var isAddress = function (address) {
|
||||||
return /^(0x)?[0-9a-f]{40}$/.test(address);
|
return /^(0x)?[0-9a-f]{40}$/.test(address);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given string is an address
|
||||||
|
*
|
||||||
|
* @method isChecksumAddress
|
||||||
|
* @param {String} address the given HEX adress
|
||||||
|
* @return {Boolean}
|
||||||
|
*/
|
||||||
|
var isChecksumAddress = function (address) {
|
||||||
|
return /^(0x)?[0-9a-f]{48}$/.test(address);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms given string to valid 20 bytes-length addres with 0x prefix
|
* Transforms given string to valid 20 bytes-length addres with 0x prefix
|
||||||
*
|
*
|
||||||
|
|
@ -2378,6 +2389,7 @@ module.exports = {
|
||||||
isBigNumber: isBigNumber,
|
isBigNumber: isBigNumber,
|
||||||
isStrictAddress: isStrictAddress,
|
isStrictAddress: isStrictAddress,
|
||||||
isAddress: isAddress,
|
isAddress: isAddress,
|
||||||
|
isChecksumAddress: isChecksumAddress,
|
||||||
isFunction: isFunction,
|
isFunction: isFunction,
|
||||||
isString: isString,
|
isString: isString,
|
||||||
isObject: isObject,
|
isObject: isObject,
|
||||||
|
|
@ -2513,6 +2525,7 @@ web3.toBigNumber = utils.toBigNumber;
|
||||||
web3.toWei = utils.toWei;
|
web3.toWei = utils.toWei;
|
||||||
web3.fromWei = utils.fromWei;
|
web3.fromWei = utils.fromWei;
|
||||||
web3.isAddress = utils.isAddress;
|
web3.isAddress = utils.isAddress;
|
||||||
|
web3.isChecksumAddress = utils.isChecksumAddress;
|
||||||
web3.isIBAN = utils.isIBAN;
|
web3.isIBAN = utils.isIBAN;
|
||||||
web3.sha3 = sha3;
|
web3.sha3 = sha3;
|
||||||
web3.createBatch = function () {
|
web3.createBatch = function () {
|
||||||
|
|
@ -3735,8 +3748,10 @@ var inputAddressFormatter = function (address) {
|
||||||
return address;
|
return address;
|
||||||
} else if (utils.isAddress(address)) {
|
} else if (utils.isAddress(address)) {
|
||||||
return '0x' + address;
|
return '0x' + address;
|
||||||
|
} else if (utils.isChecksumAddress(address)) {
|
||||||
|
return address;
|
||||||
}
|
}
|
||||||
throw 'invalid address';
|
throw 'invalid address'
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
||||||
23
xeth/xeth.go
23
xeth/xeth.go
|
|
@ -389,7 +389,7 @@ func (self *XEth) Accounts() []string {
|
||||||
accounts, _ := self.backend.AccountManager().Accounts()
|
accounts, _ := self.backend.AccountManager().Accounts()
|
||||||
accountAddresses := make([]string, len(accounts))
|
accountAddresses := make([]string, len(accounts))
|
||||||
for i, ac := range accounts {
|
for i, ac := range accounts {
|
||||||
accountAddresses[i] = ac.Address.Hex()
|
accountAddresses[i] = crypto.ChecksumAddress(ac.Address).Hex()
|
||||||
}
|
}
|
||||||
return accountAddresses
|
return accountAddresses
|
||||||
}
|
}
|
||||||
|
|
@ -890,7 +890,6 @@ func (self *XEth) Frontend() Frontend {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *XEth) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) {
|
func (self *XEth) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) {
|
||||||
|
|
||||||
// this minimalistic recoding is enough (works for natspec.js)
|
// this minimalistic recoding is enough (works for natspec.js)
|
||||||
var jsontx = fmt.Sprintf(`{"params":[{"to":"%s","data": "%s"}]}`, toStr, codeStr)
|
var jsontx = fmt.Sprintf(`{"params":[{"to":"%s","data": "%s"}]}`, toStr, codeStr)
|
||||||
if !self.ConfirmTransaction(jsontx) {
|
if !self.ConfirmTransaction(jsontx) {
|
||||||
|
|
@ -898,13 +897,27 @@ func (self *XEth) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceS
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(toStr) > 0 && toStr != "0x" && !isAddress(toStr) {
|
var (
|
||||||
return "", errors.New("Invalid address")
|
to common.Address
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
// If the address is larges than 20 bytes (+ 0x) assume a checksum
|
||||||
|
// address and verify.
|
||||||
|
if len(toStr) > 42 {
|
||||||
|
checkAddr := common.HexToChecksumAddress(toStr)
|
||||||
|
to, err = crypto.ValidateAddress(checkAddr)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if len(toStr) > 0 && toStr != "0x" && !isAddress(toStr) {
|
||||||
|
return "", errors.New("Invalid address")
|
||||||
|
}
|
||||||
|
to = common.HexToAddress(toStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
from = common.HexToAddress(fromStr)
|
from = common.HexToAddress(fromStr)
|
||||||
to = common.HexToAddress(toStr)
|
|
||||||
value = common.Big(valueStr)
|
value = common.Big(valueStr)
|
||||||
gas *big.Int
|
gas *big.Int
|
||||||
price *big.Int
|
price *big.Int
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue