github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/core/vm/contracts.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:36</date>
    10  //</624450081981992960>
    11  
    12  
    13  package vm
    14  
    15  import (
    16  	"crypto/sha256"
    17  	"errors"
    18  	"math/big"
    19  
    20  	"github.com/ethereum/go-ethereum/common"
    21  	"github.com/ethereum/go-ethereum/common/math"
    22  	"github.com/ethereum/go-ethereum/crypto"
    23  	"github.com/ethereum/go-ethereum/crypto/bn256"
    24  	"github.com/ethereum/go-ethereum/params"
    25  	"golang.org/x/crypto/ripemd160"
    26  )
    27  
    28  //预编译契约是本地Go契约的基本接口。实施
    29  //需要基于运行方法的输入大小确定的气体计数
    30  //合同。
    31  type PrecompiledContract interface {
    32  RequiredGas(input []byte) uint64  //所需价格计算合同用气
    33  Run(input []byte) ([]byte, error) //运行运行预编译合同
    34  }
    35  
    36  //预编译的ContractShomestead包含预编译的ethereum的默认集
    37  //边境地区使用的合同和宅基地释放。
    38  var PrecompiledContractsHomestead = map[common.Address]PrecompiledContract{
    39  	common.BytesToAddress([]byte{1}): &ecrecover{},
    40  	common.BytesToAddress([]byte{2}): &sha256hash{},
    41  	common.BytesToAddress([]byte{3}): &ripemd160hash{},
    42  	common.BytesToAddress([]byte{4}): &dataCopy{},
    43  }
    44  
    45  //PrecompiledContractsByzantium包含预编译的ethereum的默认集
    46  //拜占庭协议中使用的合同。
    47  var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{
    48  	common.BytesToAddress([]byte{1}): &ecrecover{},
    49  	common.BytesToAddress([]byte{2}): &sha256hash{},
    50  	common.BytesToAddress([]byte{3}): &ripemd160hash{},
    51  	common.BytesToAddress([]byte{4}): &dataCopy{},
    52  	common.BytesToAddress([]byte{5}): &bigModExp{},
    53  	common.BytesToAddress([]byte{6}): &bn256Add{},
    54  	common.BytesToAddress([]byte{7}): &bn256ScalarMul{},
    55  	common.BytesToAddress([]byte{8}): &bn256Pairing{},
    56  }
    57  
    58  //runPrecompiledContract运行并评估预编译合同的输出。
    59  func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) {
    60  	gas := p.RequiredGas(input)
    61  	if contract.UseGas(gas) {
    62  		return p.Run(input)
    63  	}
    64  	return nil, ErrOutOfGas
    65  }
    66  
    67  //ecrecover作为本机合同实现。
    68  type ecrecover struct{}
    69  
    70  func (c *ecrecover) RequiredGas(input []byte) uint64 {
    71  	return params.EcrecoverGas
    72  }
    73  
    74  func (c *ecrecover) Run(input []byte) ([]byte, error) {
    75  	const ecRecoverInputLength = 128
    76  
    77  	input = common.RightPadBytes(input, ecRecoverInputLength)
    78  //“input”是(hash、v、r、s),每个32字节
    79  //但对于ecrecover,我们需要(r,s,v)
    80  
    81  	r := new(big.Int).SetBytes(input[64:96])
    82  	s := new(big.Int).SetBytes(input[96:128])
    83  	v := input[63] - 27
    84  
    85  //更紧密的sig s值输入homestead仅适用于tx sig s
    86  	if !allZero(input[32:63]) || !crypto.ValidateSignatureValues(v, r, s, false) {
    87  		return nil, nil
    88  	}
    89  //对于libsecp256k1,v必须在末尾
    90  	pubKey, err := crypto.Ecrecover(input[:32], append(input[64:128], v))
    91  //确保公钥是有效的。
    92  	if err != nil {
    93  		return nil, nil
    94  	}
    95  
    96  //pubkey的第一个字节是比特币遗产
    97  	return common.LeftPadBytes(crypto.Keccak256(pubKey[1:])[12:], 32), nil
    98  }
    99  
   100  //sha256作为本地合同实施。
   101  type sha256hash struct{}
   102  
   103  //Requiredgas返回执行预编译合同所需的气体。
   104  //
   105  //这种方法不需要任何溢出检查作为输入尺寸的气体成本。
   106  //任何重要的事情都需要如此之高的代价。
   107  func (c *sha256hash) RequiredGas(input []byte) uint64 {
   108  	return uint64(len(input)+31)/32*params.Sha256PerWordGas + params.Sha256BaseGas
   109  }
   110  func (c *sha256hash) Run(input []byte) ([]byte, error) {
   111  	h := sha256.Sum256(input)
   112  	return h[:], nil
   113  }
   114  
   115  //ripemd160作为本地合同实施。
   116  type ripemd160hash struct{}
   117  
   118  //Requiredgas返回执行预编译合同所需的气体。
   119  //
   120  //这种方法不需要任何溢出检查作为输入尺寸的气体成本。
   121  //任何重要的事情都需要如此之高的代价。
   122  func (c *ripemd160hash) RequiredGas(input []byte) uint64 {
   123  	return uint64(len(input)+31)/32*params.Ripemd160PerWordGas + params.Ripemd160BaseGas
   124  }
   125  func (c *ripemd160hash) Run(input []byte) ([]byte, error) {
   126  	ripemd := ripemd160.New()
   127  	ripemd.Write(input)
   128  	return common.LeftPadBytes(ripemd.Sum(nil), 32), nil
   129  }
   130  
   131  //数据复制作为本机协定实现。
   132  type dataCopy struct{}
   133  
   134  //Requiredgas返回执行预编译合同所需的气体。
   135  //
   136  //这种方法不需要任何溢出检查作为输入尺寸的气体成本。
   137  //任何重要的事情都需要如此之高的代价。
   138  func (c *dataCopy) RequiredGas(input []byte) uint64 {
   139  	return uint64(len(input)+31)/32*params.IdentityPerWordGas + params.IdentityBaseGas
   140  }
   141  func (c *dataCopy) Run(in []byte) ([]byte, error) {
   142  	return in, nil
   143  }
   144  
   145  //bigmodexp实现了本机的大整数指数模块化操作。
   146  type bigModExp struct{}
   147  
   148  var (
   149  	big1      = big.NewInt(1)
   150  	big4      = big.NewInt(4)
   151  	big8      = big.NewInt(8)
   152  	big16     = big.NewInt(16)
   153  	big32     = big.NewInt(32)
   154  	big64     = big.NewInt(64)
   155  	big96     = big.NewInt(96)
   156  	big480    = big.NewInt(480)
   157  	big1024   = big.NewInt(1024)
   158  	big3072   = big.NewInt(3072)
   159  	big199680 = big.NewInt(199680)
   160  )
   161  
   162  //Requiredgas返回执行预编译合同所需的气体。
   163  func (c *bigModExp) RequiredGas(input []byte) uint64 {
   164  	var (
   165  		baseLen = new(big.Int).SetBytes(getData(input, 0, 32))
   166  		expLen  = new(big.Int).SetBytes(getData(input, 32, 32))
   167  		modLen  = new(big.Int).SetBytes(getData(input, 64, 32))
   168  	)
   169  	if len(input) > 96 {
   170  		input = input[96:]
   171  	} else {
   172  		input = input[:0]
   173  	}
   174  //为调整后的指数长度检索exp的头32字节
   175  	var expHead *big.Int
   176  	if big.NewInt(int64(len(input))).Cmp(baseLen) <= 0 {
   177  		expHead = new(big.Int)
   178  	} else {
   179  		if expLen.Cmp(big32) > 0 {
   180  			expHead = new(big.Int).SetBytes(getData(input, baseLen.Uint64(), 32))
   181  		} else {
   182  			expHead = new(big.Int).SetBytes(getData(input, baseLen.Uint64(), expLen.Uint64()))
   183  		}
   184  	}
   185  //计算调整后的指数长度
   186  	var msb int
   187  	if bitlen := expHead.BitLen(); bitlen > 0 {
   188  		msb = bitlen - 1
   189  	}
   190  	adjExpLen := new(big.Int)
   191  	if expLen.Cmp(big32) > 0 {
   192  		adjExpLen.Sub(expLen, big32)
   193  		adjExpLen.Mul(big8, adjExpLen)
   194  	}
   195  	adjExpLen.Add(adjExpLen, big.NewInt(int64(msb)))
   196  
   197  //计算操作的燃气成本
   198  	gas := new(big.Int).Set(math.BigMax(modLen, baseLen))
   199  	switch {
   200  	case gas.Cmp(big64) <= 0:
   201  		gas.Mul(gas, gas)
   202  	case gas.Cmp(big1024) <= 0:
   203  		gas = new(big.Int).Add(
   204  			new(big.Int).Div(new(big.Int).Mul(gas, gas), big4),
   205  			new(big.Int).Sub(new(big.Int).Mul(big96, gas), big3072),
   206  		)
   207  	default:
   208  		gas = new(big.Int).Add(
   209  			new(big.Int).Div(new(big.Int).Mul(gas, gas), big16),
   210  			new(big.Int).Sub(new(big.Int).Mul(big480, gas), big199680),
   211  		)
   212  	}
   213  	gas.Mul(gas, math.BigMax(adjExpLen, big1))
   214  	gas.Div(gas, new(big.Int).SetUint64(params.ModExpQuadCoeffDiv))
   215  
   216  	if gas.BitLen() > 64 {
   217  		return math.MaxUint64
   218  	}
   219  	return gas.Uint64()
   220  }
   221  
   222  func (c *bigModExp) Run(input []byte) ([]byte, error) {
   223  	var (
   224  		baseLen = new(big.Int).SetBytes(getData(input, 0, 32)).Uint64()
   225  		expLen  = new(big.Int).SetBytes(getData(input, 32, 32)).Uint64()
   226  		modLen  = new(big.Int).SetBytes(getData(input, 64, 32)).Uint64()
   227  	)
   228  	if len(input) > 96 {
   229  		input = input[96:]
   230  	} else {
   231  		input = input[:0]
   232  	}
   233  //当基本长度和模长都为零时处理特殊情况
   234  	if baseLen == 0 && modLen == 0 {
   235  		return []byte{}, nil
   236  	}
   237  //检索操作数并执行求幂
   238  	var (
   239  		base = new(big.Int).SetBytes(getData(input, 0, baseLen))
   240  		exp  = new(big.Int).SetBytes(getData(input, baseLen, expLen))
   241  		mod  = new(big.Int).SetBytes(getData(input, baseLen+expLen, modLen))
   242  	)
   243  	if mod.BitLen() == 0 {
   244  //模0未定义,返回零
   245  		return common.LeftPadBytes([]byte{}, int(modLen)), nil
   246  	}
   247  	return common.LeftPadBytes(base.Exp(base, exp, mod).Bytes(), int(modLen)), nil
   248  }
   249  
   250  //newcurvepoint将二进制blob解封为bn256椭圆曲线点,
   251  //返回它,或者如果点无效则返回错误。
   252  func newCurvePoint(blob []byte) (*bn256.G1, error) {
   253  	p := new(bn256.G1)
   254  	if _, err := p.Unmarshal(blob); err != nil {
   255  		return nil, err
   256  	}
   257  	return p, nil
   258  }
   259  
   260  //newTwistpoint将二进制斑点解组为bn256椭圆曲线点,
   261  //返回它,或者如果点无效则返回错误。
   262  func newTwistPoint(blob []byte) (*bn256.G2, error) {
   263  	p := new(bn256.G2)
   264  	if _, err := p.Unmarshal(blob); err != nil {
   265  		return nil, err
   266  	}
   267  	return p, nil
   268  }
   269  
   270  //bn256add实现本机椭圆曲线点加法。
   271  type bn256Add struct{}
   272  
   273  //Requiredgas返回执行预编译合同所需的气体。
   274  func (c *bn256Add) RequiredGas(input []byte) uint64 {
   275  	return params.Bn256AddGas
   276  }
   277  
   278  func (c *bn256Add) Run(input []byte) ([]byte, error) {
   279  	x, err := newCurvePoint(getData(input, 0, 64))
   280  	if err != nil {
   281  		return nil, err
   282  	}
   283  	y, err := newCurvePoint(getData(input, 64, 64))
   284  	if err != nil {
   285  		return nil, err
   286  	}
   287  	res := new(bn256.G1)
   288  	res.Add(x, y)
   289  	return res.Marshal(), nil
   290  }
   291  
   292  //bn256scalarmul实现本机椭圆曲线标量乘法。
   293  type bn256ScalarMul struct{}
   294  
   295  //Requiredgas返回执行预编译合同所需的气体。
   296  func (c *bn256ScalarMul) RequiredGas(input []byte) uint64 {
   297  	return params.Bn256ScalarMulGas
   298  }
   299  
   300  func (c *bn256ScalarMul) Run(input []byte) ([]byte, error) {
   301  	p, err := newCurvePoint(getData(input, 0, 64))
   302  	if err != nil {
   303  		return nil, err
   304  	}
   305  	res := new(bn256.G1)
   306  	res.ScalarMult(p, new(big.Int).SetBytes(getData(input, 64, 32)))
   307  	return res.Marshal(), nil
   308  }
   309  
   310  var (
   311  //如果bn256配对检查成功,则返回true32字节。
   312  	true32Byte = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
   313  
   314  //如果bn256配对检查失败,则返回假32byte。
   315  	false32Byte = make([]byte, 32)
   316  
   317  //如果bn256配对输入无效,则返回errbadpairinginput。
   318  	errBadPairingInput = errors.New("bad elliptic curve pairing size")
   319  )
   320  
   321  //bn256配对为bn256曲线执行配对预编译
   322  type bn256Pairing struct{}
   323  
   324  //Requiredgas返回执行预编译合同所需的气体。
   325  func (c *bn256Pairing) RequiredGas(input []byte) uint64 {
   326  	return params.Bn256PairingBaseGas + uint64(len(input)/192)*params.Bn256PairingPerPointGas
   327  }
   328  
   329  func (c *bn256Pairing) Run(input []byte) ([]byte, error) {
   330  //便宜处理一些角箱
   331  	if len(input)%192 > 0 {
   332  		return nil, errBadPairingInput
   333  	}
   334  //将输入转换为一组坐标
   335  	var (
   336  		cs []*bn256.G1
   337  		ts []*bn256.G2
   338  	)
   339  	for i := 0; i < len(input); i += 192 {
   340  		c, err := newCurvePoint(input[i : i+64])
   341  		if err != nil {
   342  			return nil, err
   343  		}
   344  		t, err := newTwistPoint(input[i+64 : i+192])
   345  		if err != nil {
   346  			return nil, err
   347  		}
   348  		cs = append(cs, c)
   349  		ts = append(ts, t)
   350  	}
   351  //执行配对检查并返回结果
   352  	if bn256.PairingCheck(cs, ts) {
   353  		return true32Byte, nil
   354  	}
   355  	return false32Byte, nil
   356  }
   357