contracts.go 2.68 KB
Newer Older
obscuren's avatar
obscuren committed
1
package vm
obscuren's avatar
obscuren committed
2 3 4 5

import (
	"math/big"

obscuren's avatar
obscuren committed
6
	"github.com/ethereum/go-ethereum/common"
7
	"github.com/ethereum/go-ethereum/crypto"
8
	"github.com/ethereum/go-ethereum/logger"
9
	"github.com/ethereum/go-ethereum/logger/glog"
10
	"github.com/ethereum/go-ethereum/params"
obscuren's avatar
obscuren committed
11 12 13 14 15 16
)

type Address interface {
	Call(in []byte) []byte
}

17
type PrecompiledAccount struct {
obscuren's avatar
obscuren committed
18
	Gas func(l int) *big.Int
obscuren's avatar
obscuren committed
19 20 21
	fn  func(in []byte) []byte
}

22
func (self PrecompiledAccount) Call(in []byte) []byte {
obscuren's avatar
obscuren committed
23 24 25
	return self.fn(in)
}

obscuren's avatar
obscuren committed
26 27 28 29 30 31
var Precompiled = PrecompiledContracts()

// XXX Could set directly. Testing requires resetting and setting of pre compiled contracts.
func PrecompiledContracts() map[string]*PrecompiledAccount {
	return map[string]*PrecompiledAccount{
		// ECRECOVER
obscuren's avatar
obscuren committed
32
		string(common.LeftPadBytes([]byte{1}, 20)): &PrecompiledAccount{func(l int) *big.Int {
33
			return params.EcrecoverGas
obscuren's avatar
obscuren committed
34 35 36
		}, ecrecoverFunc},

		// SHA256
obscuren's avatar
obscuren committed
37
		string(common.LeftPadBytes([]byte{2}, 20)): &PrecompiledAccount{func(l int) *big.Int {
obscuren's avatar
obscuren committed
38
			n := big.NewInt(int64(l+31) / 32)
39 40
			n.Mul(n, params.Sha256WordGas)
			return n.Add(n, params.Sha256Gas)
obscuren's avatar
obscuren committed
41 42 43
		}, sha256Func},

		// RIPEMD160
obscuren's avatar
obscuren committed
44
		string(common.LeftPadBytes([]byte{3}, 20)): &PrecompiledAccount{func(l int) *big.Int {
obscuren's avatar
obscuren committed
45
			n := big.NewInt(int64(l+31) / 32)
46 47
			n.Mul(n, params.Ripemd160WordGas)
			return n.Add(n, params.Ripemd160Gas)
obscuren's avatar
obscuren committed
48 49
		}, ripemd160Func},

obscuren's avatar
obscuren committed
50
		string(common.LeftPadBytes([]byte{4}, 20)): &PrecompiledAccount{func(l int) *big.Int {
obscuren's avatar
obscuren committed
51
			n := big.NewInt(int64(l+31) / 32)
52
			n.Mul(n, params.IdentityWordGas)
obscuren's avatar
obscuren committed
53

54
			return n.Add(n, params.IdentityGas)
obscuren's avatar
obscuren committed
55 56
		}, memCpy},
	}
obscuren's avatar
obscuren committed
57 58 59
}

func sha256Func(in []byte) []byte {
obscuren's avatar
obscuren committed
60
	return crypto.Sha256(in)
obscuren's avatar
obscuren committed
61 62 63
}

func ripemd160Func(in []byte) []byte {
obscuren's avatar
obscuren committed
64
	return common.LeftPadBytes(crypto.Ripemd160(in), 32)
obscuren's avatar
obscuren committed
65 66
}

obscuren's avatar
obscuren committed
67
const ecRecoverInputLength = 128
obscuren's avatar
obscuren committed
68

69
func ecrecoverFunc(in []byte) []byte {
70
	in = common.RightPadBytes(in, 128)
71 72
	// "in" is (hash, v, r, s), each 32 bytes
	// but for ecrecover we want (r, s, v)
obscuren's avatar
obscuren committed
73

74 75
	r := common.BytesToBig(in[64:96])
	s := common.BytesToBig(in[96:128])
obscuren's avatar
obscuren committed
76
	// Treat V as a 256bit integer
77 78 79 80 81
	vbig := common.Bytes2Big(in[32:64])
	v := byte(vbig.Uint64())

	if !crypto.ValidateSignatureValues(v, r, s) {
		glog.V(logger.Error).Infof("EC RECOVER FAIL: v, r or s value invalid")
82 83
		return nil
	}
obscuren's avatar
obscuren committed
84

85 86 87 88
	// v needs to be at the end and normalized for libsecp256k1
	vbignormal := new(big.Int).Sub(vbig, big.NewInt(27))
	vnormal := byte(vbignormal.Uint64())
	rsv := append(in[64:128], vnormal)
89
	pubKey, err := crypto.Ecrecover(in[:32], rsv)
obscuren's avatar
obscuren committed
90
	// make sure the public key is a valid one
91
	if err != nil {
92
		glog.V(logger.Error).Infof("EC RECOVER FAIL: ", err)
93 94
		return nil
	}
obscuren's avatar
obscuren committed
95

96 97
	// the first byte of pubkey is bitcoin heritage
	return common.LeftPadBytes(crypto.Sha3(pubKey[1:])[12:], 32)
obscuren's avatar
obscuren committed
98
}
99 100 101 102

func memCpy(in []byte) []byte {
	return in
}