github.com/core-coin/go-core@v1.1.7/core/vm/contracts.go (about) 1 // Copyright 2014 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core 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-core 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-core library. If not, see <http://www.gnu.org/licenses/>. 16 17 package vm 18 19 import ( 20 "crypto/sha256" 21 "encoding/binary" 22 "errors" 23 "github.com/core-coin/go-goldilocks" 24 "golang.org/x/crypto/sha3" 25 "math/big" 26 27 "github.com/core-coin/go-core/common" 28 "github.com/core-coin/go-core/common/math" 29 "github.com/core-coin/go-core/crypto" 30 "github.com/core-coin/go-core/crypto/blake2b" 31 "github.com/core-coin/go-core/crypto/bn256" 32 "github.com/core-coin/go-core/params" 33 34 //lint:ignore SA1019 Needed for precompile 35 "golang.org/x/crypto/ripemd160" 36 ) 37 38 // PrecompiledContract is the basic interface for native Go contracts. The implementation 39 // requires a deterministic energy count based on the input size of the Run method of the 40 // contract. 41 type PrecompiledContract interface { 42 RequiredEnergy(input []byte) uint64 // RequiredPrice calculates the contract energy use 43 Run(input []byte) ([]byte, error) // Run runs the precompiled contract 44 } 45 46 var PrecompiledContracts = map[common.Address]PrecompiledContract{ 47 common.Addr1: &ecrecover{}, 48 common.Addr2: &sha256hash{}, 49 common.Addr3: &ripemd160hash{}, 50 common.Addr4: &dataCopy{}, 51 common.Addr5: &bigModExp{}, 52 common.Addr6: &bn256Add{}, 53 common.Addr7: &bn256ScalarMul{}, 54 common.Addr8: &bn256Pairing{}, 55 common.Addr9: &blake2F{}, 56 } 57 58 // RunPrecompiledContract runs and evaluates the output of a precompiled contract. 59 // It returns 60 // - the returned bytes, 61 // - the _remaining_ energy, 62 // - any error that occurred 63 func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedEnergy uint64) (ret []byte, remainingEnergy uint64, err error) { 64 energyCost := p.RequiredEnergy(input) 65 if suppliedEnergy < energyCost { 66 return nil, 0, ErrOutOfEnergy 67 } 68 suppliedEnergy -= energyCost 69 output, err := p.Run(input) 70 return output, suppliedEnergy, err 71 } 72 73 // ECRECOVER implemented as a native contract. 74 type ecrecover struct{} 75 76 func (c *ecrecover) RequiredEnergy(input []byte) uint64 { 77 return params.EcrecoverEnergy 78 } 79 80 func (c *ecrecover) Run(input []byte) ([]byte, error) { 81 var ecRecoverInputLength = sha3.New256().Size() + crypto.ExtendedSignatureLength // 32 + 171 82 83 input = common.RightPadBytes(input, ecRecoverInputLength) 84 85 pubKey, err := crypto.Ecrecover(input[:32], input[96:267]) 86 // make sure the public key is a valid one 87 if err != nil { 88 return nil, nil 89 } 90 if pubKey != nil { 91 return common.LeftPadBytes(crypto.PubkeyToAddress(goldilocks.BytesToPublicKey(pubKey)).Bytes(), 32), nil 92 } 93 return nil, errors.New("invalid signature") 94 } 95 96 // SHA256 implemented as a native contract. 97 type sha256hash struct{} 98 99 // RequiredEnergy returns the energy required to execute the pre-compiled contract. 100 // 101 // This method does not require any overflow checking as the input size energy costs 102 // required for anything significant is so high it's impossible to pay for. 103 func (c *sha256hash) RequiredEnergy(input []byte) uint64 { 104 return uint64(len(input)+31)/32*params.Sha256PerWordEnergy + params.Sha256BaseEnergy 105 } 106 func (c *sha256hash) Run(input []byte) ([]byte, error) { 107 h := sha256.Sum256(input) 108 return h[:], nil 109 } 110 111 // RIPEMD160 implemented as a native contract. 112 type ripemd160hash struct{} 113 114 // RequiredEnergy returns the energy required to execute the pre-compiled contract. 115 // 116 // This method does not require any overflow checking as the input size energy costs 117 // required for anything significant is so high it's impossible to pay for. 118 func (c *ripemd160hash) RequiredEnergy(input []byte) uint64 { 119 return uint64(len(input)+31)/32*params.Ripemd160PerWordEnergy + params.Ripemd160BaseEnergy 120 } 121 func (c *ripemd160hash) Run(input []byte) ([]byte, error) { 122 ripemd := ripemd160.New() 123 ripemd.Write(input) 124 return common.LeftPadBytes(ripemd.Sum(nil), 32), nil 125 } 126 127 // data copy implemented as a native contract. 128 type dataCopy struct{} 129 130 // RequiredEnergy returns the energy required to execute the pre-compiled contract. 131 // 132 // This method does not require any overflow checking as the input size energy costs 133 // required for anything significant is so high it's impossible to pay for. 134 func (c *dataCopy) RequiredEnergy(input []byte) uint64 { 135 return uint64(len(input)+31)/32*params.IdentityPerWordEnergy + params.IdentityBaseEnergy 136 } 137 func (c *dataCopy) Run(in []byte) ([]byte, error) { 138 return in, nil 139 } 140 141 // bigModExp implements a native big integer exponential modular operation. 142 type bigModExp struct{} 143 144 var ( 145 big0 = big.NewInt(0) 146 big1 = big.NewInt(1) 147 big4 = big.NewInt(4) 148 big8 = big.NewInt(8) 149 big16 = big.NewInt(16) 150 big32 = big.NewInt(32) 151 big64 = big.NewInt(64) 152 big96 = big.NewInt(96) 153 big480 = big.NewInt(480) 154 big1024 = big.NewInt(1024) 155 big3072 = big.NewInt(3072) 156 big199680 = big.NewInt(199680) 157 ) 158 159 // RequiredEnergy returns the energy required to execute the pre-compiled contract. 160 func (c *bigModExp) RequiredEnergy(input []byte) uint64 { 161 var ( 162 baseLen = new(big.Int).SetBytes(getData(input, 0, 32)) 163 expLen = new(big.Int).SetBytes(getData(input, 32, 32)) 164 modLen = new(big.Int).SetBytes(getData(input, 64, 32)) 165 ) 166 if len(input) > 96 { 167 input = input[96:] 168 } else { 169 input = input[:0] 170 } 171 // Retrieve the head 32 bytes of exp for the adjusted exponent length 172 var expHead *big.Int 173 if big.NewInt(int64(len(input))).Cmp(baseLen) <= 0 { 174 expHead = new(big.Int) 175 } else { 176 if expLen.Cmp(big32) > 0 { 177 expHead = new(big.Int).SetBytes(getData(input, baseLen.Uint64(), 32)) 178 } else { 179 expHead = new(big.Int).SetBytes(getData(input, baseLen.Uint64(), expLen.Uint64())) 180 } 181 } 182 // Calculate the adjusted exponent length 183 var msb int 184 if bitlen := expHead.BitLen(); bitlen > 0 { 185 msb = bitlen - 1 186 } 187 adjExpLen := new(big.Int) 188 if expLen.Cmp(big32) > 0 { 189 adjExpLen.Sub(expLen, big32) 190 adjExpLen.Mul(big8, adjExpLen) 191 } 192 adjExpLen.Add(adjExpLen, big.NewInt(int64(msb))) 193 194 // Calculate the energy cost of the operation 195 energy := new(big.Int).Set(math.BigMax(modLen, baseLen)) 196 switch { 197 case energy.Cmp(big64) <= 0: 198 energy.Mul(energy, energy) 199 case energy.Cmp(big1024) <= 0: 200 energy = new(big.Int).Add( 201 new(big.Int).Div(new(big.Int).Mul(energy, energy), big4), 202 new(big.Int).Sub(new(big.Int).Mul(big96, energy), big3072), 203 ) 204 default: 205 energy = new(big.Int).Add( 206 new(big.Int).Div(new(big.Int).Mul(energy, energy), big16), 207 new(big.Int).Sub(new(big.Int).Mul(big480, energy), big199680), 208 ) 209 } 210 energy.Mul(energy, math.BigMax(adjExpLen, big1)) 211 energy.Div(energy, new(big.Int).SetUint64(params.ModExpQuadCoeffDiv)) 212 213 if energy.BitLen() > 64 { 214 return math.MaxUint64 215 } 216 return energy.Uint64() 217 } 218 219 func (c *bigModExp) Run(input []byte) ([]byte, error) { 220 var ( 221 baseLen = new(big.Int).SetBytes(getData(input, 0, 32)).Uint64() 222 expLen = new(big.Int).SetBytes(getData(input, 32, 32)).Uint64() 223 modLen = new(big.Int).SetBytes(getData(input, 64, 32)).Uint64() 224 ) 225 if len(input) > 96 { 226 input = input[96:] 227 } else { 228 input = input[:0] 229 } 230 // Handle a special case when both the base and mod length is zero 231 if baseLen == 0 && modLen == 0 { 232 return []byte{}, nil 233 } 234 // Retrieve the operands and execute the exponentiation 235 var ( 236 base = new(big.Int).SetBytes(getData(input, 0, baseLen)) 237 exp = new(big.Int).SetBytes(getData(input, baseLen, expLen)) 238 mod = new(big.Int).SetBytes(getData(input, baseLen+expLen, modLen)) 239 ) 240 if mod.BitLen() == 0 { 241 // Modulo 0 is undefined, return zero 242 return common.LeftPadBytes([]byte{}, int(modLen)), nil 243 } 244 return common.LeftPadBytes(base.Exp(base, exp, mod).Bytes(), int(modLen)), nil 245 } 246 247 // newCurvePoint unmarshals a binary blob into a bn256 elliptic curve point, 248 // returning it, or an error if the point is invalid. 249 func newCurvePoint(blob []byte) (*bn256.G1, error) { 250 p := new(bn256.G1) 251 if _, err := p.Unmarshal(blob); err != nil { 252 return nil, err 253 } 254 return p, nil 255 } 256 257 // newTwistPoint unmarshals a binary blob into a bn256 elliptic curve point, 258 // returning it, or an error if the point is invalid. 259 func newTwistPoint(blob []byte) (*bn256.G2, error) { 260 p := new(bn256.G2) 261 if _, err := p.Unmarshal(blob); err != nil { 262 return nil, err 263 } 264 return p, nil 265 } 266 267 // runBn256Add implements the Bn256Add precompile 268 func runBn256Add(input []byte) ([]byte, error) { 269 x, err := newCurvePoint(getData(input, 0, 64)) 270 if err != nil { 271 return nil, err 272 } 273 y, err := newCurvePoint(getData(input, 64, 64)) 274 if err != nil { 275 return nil, err 276 } 277 res := new(bn256.G1) 278 res.Add(x, y) 279 return res.Marshal(), nil 280 } 281 282 // bn256Add implements a native elliptic curve point addition conforming to 283 // consensus rules. 284 type bn256Add struct{} 285 286 // RequiredEnergy returns the energy required to execute the pre-compiled contract. 287 func (c *bn256Add) RequiredEnergy(input []byte) uint64 { 288 return params.Bn256AddEnergy 289 } 290 291 func (c *bn256Add) Run(input []byte) ([]byte, error) { 292 return runBn256Add(input) 293 } 294 295 // runBn256ScalarMul implements the Bn256ScalarMul precompile 296 func runBn256ScalarMul(input []byte) ([]byte, error) { 297 p, err := newCurvePoint(getData(input, 0, 64)) 298 if err != nil { 299 return nil, err 300 } 301 res := new(bn256.G1) 302 res.ScalarMult(p, new(big.Int).SetBytes(getData(input, 64, 32))) 303 return res.Marshal(), nil 304 } 305 306 // bn256ScalarMul implements a native elliptic curve scalar 307 // multiplication conforming to consensus rules. 308 type bn256ScalarMul struct{} 309 310 // RequiredEnergy returns the energy required to execute the pre-compiled contract. 311 func (c *bn256ScalarMul) RequiredEnergy(input []byte) uint64 { 312 return params.Bn256ScalarMulEnergy 313 } 314 315 func (c *bn256ScalarMul) Run(input []byte) ([]byte, error) { 316 return runBn256ScalarMul(input) 317 } 318 319 var ( 320 // true32Byte is returned if the bn256 pairing check succeeds. 321 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} 322 323 // false32Byte is returned if the bn256 pairing check fails. 324 false32Byte = make([]byte, 32) 325 326 // errBadPairingInput is returned if the bn256 pairing input is invalid. 327 errBadPairingInput = errors.New("bad elliptic curve pairing size") 328 ) 329 330 // runBn256Pairing implements the Bn256Pairing precompile 331 func runBn256Pairing(input []byte) ([]byte, error) { 332 // Handle some corner cases cheaply 333 if len(input)%192 > 0 { 334 return nil, errBadPairingInput 335 } 336 // Convert the input into a set of coordinates 337 var ( 338 cs []*bn256.G1 339 ts []*bn256.G2 340 ) 341 for i := 0; i < len(input); i += 192 { 342 c, err := newCurvePoint(input[i : i+64]) 343 if err != nil { 344 return nil, err 345 } 346 t, err := newTwistPoint(input[i+64 : i+192]) 347 if err != nil { 348 return nil, err 349 } 350 cs = append(cs, c) 351 ts = append(ts, t) 352 } 353 // Execute the pairing checks and return the results 354 if bn256.PairingCheck(cs, ts) { 355 return true32Byte, nil 356 } 357 return false32Byte, nil 358 } 359 360 // bn256Pairing implements a pairing pre-compile for the bn256 curve 361 type bn256Pairing struct{} 362 363 // RequiredEnergy returns the energy required to execute the pre-compiled contract. 364 func (c *bn256Pairing) RequiredEnergy(input []byte) uint64 { 365 return params.Bn256PairingBaseEnergy + uint64(len(input)/192)*params.Bn256PairingPerPointEnergy 366 } 367 368 func (c *bn256Pairing) Run(input []byte) ([]byte, error) { 369 return runBn256Pairing(input) 370 } 371 372 type blake2F struct{} 373 374 func (c *blake2F) RequiredEnergy(input []byte) uint64 { 375 // If the input is malformed, we can't calculate the energy, return 0 and let the 376 // actual call choke and fault. 377 if len(input) != blake2FInputLength { 378 return 0 379 } 380 return uint64(binary.BigEndian.Uint32(input[0:4])) 381 } 382 383 const ( 384 blake2FInputLength = 213 385 blake2FFinalBlockBytes = byte(1) 386 blake2FNonFinalBlockBytes = byte(0) 387 ) 388 389 var ( 390 errBlake2FInvalidInputLength = errors.New("invalid input length") 391 errBlake2FInvalidFinalFlag = errors.New("invalid final flag") 392 ) 393 394 func (c *blake2F) Run(input []byte) ([]byte, error) { 395 // Make sure the input is valid (correct lenth and final flag) 396 if len(input) != blake2FInputLength { 397 return nil, errBlake2FInvalidInputLength 398 } 399 if input[212] != blake2FNonFinalBlockBytes && input[212] != blake2FFinalBlockBytes { 400 return nil, errBlake2FInvalidFinalFlag 401 } 402 // Parse the input into the Blake2b call parameters 403 var ( 404 rounds = binary.BigEndian.Uint32(input[0:4]) 405 final = (input[212] == blake2FFinalBlockBytes) 406 407 h [8]uint64 408 m [16]uint64 409 t [2]uint64 410 ) 411 for i := 0; i < 8; i++ { 412 offset := 4 + i*8 413 h[i] = binary.LittleEndian.Uint64(input[offset : offset+8]) 414 } 415 for i := 0; i < 16; i++ { 416 offset := 68 + i*8 417 m[i] = binary.LittleEndian.Uint64(input[offset : offset+8]) 418 } 419 t[0] = binary.LittleEndian.Uint64(input[196:204]) 420 t[1] = binary.LittleEndian.Uint64(input[204:212]) 421 422 // Execute the compression function, extract and return the result 423 blake2b.F(&h, m, t, final, rounds) 424 425 output := make([]byte, 64) 426 for i := 0; i < 8; i++ { 427 offset := i * 8 428 binary.LittleEndian.PutUint64(output[offset:offset+8], h[i]) 429 } 430 return output, nil 431 }