github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/core/vm/contracts.go (about)

     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  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     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  // GNU Lesser General Public License for more details.
    13  //
    14  // 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  
    17  package vm
    18  
    19  import (
    20  	"math/big"
    21  
    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"
    27  )
    28  
    29  type Address interface {
    30  	Call(in []byte) []byte
    31  }
    32  
    33  type PrecompiledAccount struct {
    34  	Gas func(l int) *big.Int
    35  	fn  func(in []byte) []byte
    36  }
    37  
    38  func (self PrecompiledAccount) Call(in []byte) []byte {
    39  	return self.fn(in)
    40  }
    41  
    42  var Precompiled = PrecompiledContracts()
    43  
    44  // XXX Could set directly. Testing requires resetting and setting of pre compiled contracts.
    45  func PrecompiledContracts() map[string]*PrecompiledAccount {
    46  	return map[string]*PrecompiledAccount{
    47  		// ECRECOVER
    48  		string(common.LeftPadBytes([]byte{1}, 20)): &PrecompiledAccount{func(l int) *big.Int {
    49  			return params.EcrecoverGas
    50  		}, ecrecoverFunc},
    51  
    52  		// SHA256
    53  		string(common.LeftPadBytes([]byte{2}, 20)): &PrecompiledAccount{func(l int) *big.Int {
    54  			n := big.NewInt(int64(l+31) / 32)
    55  			n.Mul(n, params.Sha256WordGas)
    56  			return n.Add(n, params.Sha256Gas)
    57  		}, sha256Func},
    58  
    59  		// RIPEMD160
    60  		string(common.LeftPadBytes([]byte{3}, 20)): &PrecompiledAccount{func(l int) *big.Int {
    61  			n := big.NewInt(int64(l+31) / 32)
    62  			n.Mul(n, params.Ripemd160WordGas)
    63  			return n.Add(n, params.Ripemd160Gas)
    64  		}, ripemd160Func},
    65  
    66  		string(common.LeftPadBytes([]byte{4}, 20)): &PrecompiledAccount{func(l int) *big.Int {
    67  			n := big.NewInt(int64(l+31) / 32)
    68  			n.Mul(n, params.IdentityWordGas)
    69  
    70  			return n.Add(n, params.IdentityGas)
    71  		}, memCpy},
    72  	}
    73  }
    74  
    75  func sha256Func(in []byte) []byte {
    76  	return crypto.Sha256(in)
    77  }
    78  
    79  func ripemd160Func(in []byte) []byte {
    80  	return common.LeftPadBytes(crypto.Ripemd160(in), 32)
    81  }
    82  
    83  const ecRecoverInputLength = 128
    84  
    85  func ecrecoverFunc(in []byte) []byte {
    86  	in = common.RightPadBytes(in, 128)
    87  	// "in" is (hash, v, r, s), each 32 bytes
    88  	// but for ecrecover we want (r, s, v)
    89  
    90  	r := common.BytesToBig(in[64:96])
    91  	s := common.BytesToBig(in[96:128])
    92  	// Treat V as a 256bit integer
    93  	vbig := common.Bytes2Big(in[32:64])
    94  	v := byte(vbig.Uint64())
    95  
    96  	if !crypto.ValidateSignatureValues(v, r, s) {
    97  		glog.V(logger.Debug).Infof("EC RECOVER FAIL: v, r or s value invalid")
    98  		return nil
    99  	}
   100  
   101  	// v needs to be at the end and normalized for libsecp256k1
   102  	vbignormal := new(big.Int).Sub(vbig, big.NewInt(27))
   103  	vnormal := byte(vbignormal.Uint64())
   104  	rsv := append(in[64:128], vnormal)
   105  	pubKey, err := crypto.Ecrecover(in[:32], rsv)
   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  		return nil
   110  	}
   111  
   112  	// the first byte of pubkey is bitcoin heritage
   113  	return common.LeftPadBytes(crypto.Sha3(pubKey[1:])[12:], 32)
   114  }
   115  
   116  func memCpy(in []byte) []byte {
   117  	return in
   118  }