contracts.go 3.45 KB
Newer Older
1
// Copyright 2014 The go-ethereum Authors
2
// This file is part of the go-ethereum library.
3
//
4
// The go-ethereum library is free software: you can redistribute it and/or modify
5 6 7 8
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
9
// The go-ethereum library is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 13 14
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
15
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16

obscuren's avatar
obscuren committed
17
package vm
obscuren's avatar
obscuren committed
18 19 20 21

import (
	"math/big"

obscuren's avatar
obscuren committed
22
	"github.com/ethereum/go-ethereum/common"
23
	"github.com/ethereum/go-ethereum/crypto"
24
	"github.com/ethereum/go-ethereum/logger"
25
	"github.com/ethereum/go-ethereum/logger/glog"
26
	"github.com/ethereum/go-ethereum/params"
obscuren's avatar
obscuren committed
27 28 29 30 31 32
)

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

33
type PrecompiledAccount struct {
obscuren's avatar
obscuren committed
34
	Gas func(l int) *big.Int
obscuren's avatar
obscuren committed
35 36 37
	fn  func(in []byte) []byte
}

38
func (self PrecompiledAccount) Call(in []byte) []byte {
obscuren's avatar
obscuren committed
39 40 41
	return self.fn(in)
}

obscuren's avatar
obscuren committed
42 43 44 45 46 47
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
48
		string(common.LeftPadBytes([]byte{1}, 20)): &PrecompiledAccount{func(l int) *big.Int {
49
			return params.EcrecoverGas
obscuren's avatar
obscuren committed
50 51 52
		}, ecrecoverFunc},

		// SHA256
obscuren's avatar
obscuren committed
53
		string(common.LeftPadBytes([]byte{2}, 20)): &PrecompiledAccount{func(l int) *big.Int {
obscuren's avatar
obscuren committed
54
			n := big.NewInt(int64(l+31) / 32)
55 56
			n.Mul(n, params.Sha256WordGas)
			return n.Add(n, params.Sha256Gas)
obscuren's avatar
obscuren committed
57 58 59
		}, sha256Func},

		// RIPEMD160
obscuren's avatar
obscuren committed
60
		string(common.LeftPadBytes([]byte{3}, 20)): &PrecompiledAccount{func(l int) *big.Int {
obscuren's avatar
obscuren committed
61
			n := big.NewInt(int64(l+31) / 32)
62 63
			n.Mul(n, params.Ripemd160WordGas)
			return n.Add(n, params.Ripemd160Gas)
obscuren's avatar
obscuren committed
64 65
		}, ripemd160Func},

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

70
			return n.Add(n, params.IdentityGas)
obscuren's avatar
obscuren committed
71 72
		}, memCpy},
	}
obscuren's avatar
obscuren committed
73 74 75
}

func sha256Func(in []byte) []byte {
obscuren's avatar
obscuren committed
76
	return crypto.Sha256(in)
obscuren's avatar
obscuren committed
77 78 79
}

func ripemd160Func(in []byte) []byte {
obscuren's avatar
obscuren committed
80
	return common.LeftPadBytes(crypto.Ripemd160(in), 32)
obscuren's avatar
obscuren committed
81 82
}

obscuren's avatar
obscuren committed
83
const ecRecoverInputLength = 128
obscuren's avatar
obscuren committed
84

85
func ecrecoverFunc(in []byte) []byte {
86
	in = common.RightPadBytes(in, 128)
87 88
	// "in" is (hash, v, r, s), each 32 bytes
	// but for ecrecover we want (r, s, v)
obscuren's avatar
obscuren committed
89

90 91
	r := common.BytesToBig(in[64:96])
	s := common.BytesToBig(in[96:128])
obscuren's avatar
obscuren committed
92
	// Treat V as a 256bit integer
93 94 95 96 97
	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")
98 99
		return nil
	}
obscuren's avatar
obscuren committed
100

101 102 103 104
	// 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)
105
	pubKey, err := crypto.Ecrecover(in[:32], rsv)
obscuren's avatar
obscuren committed
106
	// make sure the public key is a valid one
107
	if err != nil {
108
		glog.V(logger.Error).Infof("EC RECOVER FAIL: ", err)
109 110
		return nil
	}
obscuren's avatar
obscuren committed
111

112 113
	// the first byte of pubkey is bitcoin heritage
	return common.LeftPadBytes(crypto.Sha3(pubKey[1:])[12:], 32)
obscuren's avatar
obscuren committed
114
}
115 116 117 118

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