2018-10-02 14:46:39 +00:00
|
|
|
import
|
2021-06-01 11:04:47 +00:00
|
|
|
./types, ../forks,
|
|
|
|
./interpreter/[gas_meter, gas_costs, utils/utils_numeric],
|
2021-04-01 11:53:22 +00:00
|
|
|
../errors, stint, eth/[keys, common], chronicles, tables, macros,
|
|
|
|
math, nimcrypto, bncurve/[fields, groups], ./blake2b_f, ./blscurve
|
2018-10-02 14:46:39 +00:00
|
|
|
|
|
|
|
type
|
2018-10-10 16:36:11 +00:00
|
|
|
PrecompileAddresses* = enum
|
2019-04-02 06:05:42 +00:00
|
|
|
# Frontier to Spurious Dragron
|
2020-11-27 14:42:17 +00:00
|
|
|
paEcRecover = 1
|
|
|
|
paSha256
|
|
|
|
paRipeMd160
|
|
|
|
paIdentity
|
2019-11-11 04:21:16 +00:00
|
|
|
# Byzantium and Constantinople
|
2020-11-27 14:42:17 +00:00
|
|
|
paModExp
|
|
|
|
paEcAdd
|
|
|
|
paEcMul
|
|
|
|
paPairing
|
2019-11-11 04:21:16 +00:00
|
|
|
# Istanbul
|
2020-11-27 14:42:17 +00:00
|
|
|
paBlake2bf
|
|
|
|
# Berlin
|
2021-05-16 12:44:24 +00:00
|
|
|
# EIP 2537: disabled
|
|
|
|
# reason: not included in berlin
|
|
|
|
# paBlsG1Add
|
|
|
|
# paBlsG1Mul
|
|
|
|
# paBlsG1MultiExp
|
|
|
|
# paBlsG2Add
|
|
|
|
# paBlsG2Mul
|
|
|
|
# paBlsG2MultiExp
|
|
|
|
# paBlsPairing
|
|
|
|
# paBlsMapG1
|
|
|
|
# paBlsMapG2
|
2018-10-02 14:46:39 +00:00
|
|
|
|
2020-12-11 10:51:17 +00:00
|
|
|
iterator activePrecompiles*(): EthAddress =
|
|
|
|
var res: EthAddress
|
|
|
|
for c in PrecompileAddresses.low..PrecompileAddresses.high:
|
|
|
|
res[^1] = c.byte
|
|
|
|
yield res
|
|
|
|
|
2020-01-10 01:26:17 +00:00
|
|
|
proc getSignature(computation: Computation): (array[32, byte], Signature) =
|
2018-10-10 16:36:11 +00:00
|
|
|
# input is Hash, V, R, S
|
|
|
|
template data: untyped = computation.msg.data
|
2019-07-19 09:38:08 +00:00
|
|
|
var bytes: array[65, byte] # will hold R[32], S[32], V[1], in that order
|
2018-10-10 16:36:11 +00:00
|
|
|
let maxPos = min(data.high, 127)
|
2019-07-19 09:38:08 +00:00
|
|
|
|
|
|
|
# if we don't have at minimum 64 bytes, there can be no valid V
|
2019-07-19 08:56:47 +00:00
|
|
|
if maxPos >= 63:
|
2019-07-19 09:38:08 +00:00
|
|
|
let v = data[63]
|
|
|
|
# check if V[32] is 27 or 28
|
|
|
|
if not (v.int in 27..28):
|
|
|
|
raise newException(ValidationError, "Invalid V in getSignature")
|
|
|
|
for x in 32..<63:
|
|
|
|
if data[x] != 0:
|
|
|
|
raise newException(ValidationError, "Invalid V in getSignature")
|
|
|
|
|
|
|
|
bytes[64] = v - 27
|
|
|
|
|
|
|
|
# if there is more data for R and S, copy it. Else, defaulted zeroes are
|
|
|
|
# used for R and S
|
|
|
|
if maxPos >= 64:
|
2018-10-10 16:36:11 +00:00
|
|
|
# Copy message data to buffer
|
2019-04-24 13:42:16 +00:00
|
|
|
bytes[0..(maxPos-64)] = data[64..maxPos]
|
|
|
|
|
2020-04-05 13:12:48 +00:00
|
|
|
let sig = Signature.fromRaw(bytes)
|
|
|
|
if sig.isErr:
|
2019-07-19 09:38:08 +00:00
|
|
|
raise newException(ValidationError, "Could not recover signature computation")
|
2020-04-05 13:12:48 +00:00
|
|
|
result[1] = sig[]
|
2018-12-04 13:39:10 +00:00
|
|
|
|
2019-07-19 09:38:08 +00:00
|
|
|
# extract message hash, only need to copy when there is a valid signature
|
|
|
|
result[0][0..31] = data[0..31]
|
|
|
|
else:
|
|
|
|
raise newException(ValidationError, "Invalid V in getSignature")
|
2018-10-02 14:46:39 +00:00
|
|
|
|
2020-12-02 09:17:52 +00:00
|
|
|
proc simpleDecode*(dst: var FQ2, src: openarray[byte]): bool {.noinit.} =
|
|
|
|
# bypassing FQ2.fromBytes
|
|
|
|
# because we want to check `value > modulus`
|
|
|
|
result = false
|
|
|
|
if dst.c1.fromBytes(src.toOpenArray(0, 31)) and
|
|
|
|
dst.c0.fromBytes(src.toOpenArray(32, 63)):
|
|
|
|
result = true
|
|
|
|
|
|
|
|
template simpleDecode*(dst: var FQ, src: openarray[byte]): bool =
|
|
|
|
fromBytes(dst, src)
|
|
|
|
|
2018-10-05 09:15:04 +00:00
|
|
|
proc getPoint[T: G1|G2](t: typedesc[T], data: openarray[byte]): Point[T] =
|
|
|
|
when T is G1:
|
|
|
|
const nextOffset = 32
|
|
|
|
var px, py: FQ
|
|
|
|
else:
|
|
|
|
const nextOffset = 64
|
|
|
|
var px, py: FQ2
|
2020-12-02 09:17:52 +00:00
|
|
|
if not px.simpleDecode(data.toOpenArray(0, nextOffset - 1)):
|
2018-10-05 09:15:04 +00:00
|
|
|
raise newException(ValidationError, "Could not get point value")
|
2020-12-02 09:17:52 +00:00
|
|
|
if not py.simpleDecode(data.toOpenArray(nextOffset, nextOffset * 2 - 1)):
|
2018-10-05 09:15:04 +00:00
|
|
|
raise newException(ValidationError, "Could not get point value")
|
2019-04-25 15:33:26 +00:00
|
|
|
|
2018-10-05 09:15:04 +00:00
|
|
|
if px.isZero() and py.isZero():
|
|
|
|
result = T.zero()
|
|
|
|
else:
|
|
|
|
var ap: AffinePoint[T]
|
|
|
|
if not ap.init(px, py):
|
|
|
|
raise newException(ValidationError, "Point is not on curve")
|
|
|
|
result = ap.toJacobian()
|
|
|
|
|
|
|
|
proc getFR(data: openarray[byte]): FR =
|
2018-10-16 08:49:13 +00:00
|
|
|
if not result.fromBytes2(data):
|
2018-10-05 09:15:04 +00:00
|
|
|
raise newException(ValidationError, "Could not get FR value")
|
|
|
|
|
2020-01-10 01:26:17 +00:00
|
|
|
proc ecRecover*(computation: Computation) =
|
2018-10-02 14:46:39 +00:00
|
|
|
computation.gasMeter.consumeGas(
|
2018-10-03 16:59:41 +00:00
|
|
|
GasECRecover,
|
2018-10-02 14:46:39 +00:00
|
|
|
reason="ECRecover Precompile")
|
|
|
|
|
|
|
|
var
|
2018-10-10 16:36:11 +00:00
|
|
|
(msgHash, sig) = computation.getSignature()
|
2018-10-02 14:46:39 +00:00
|
|
|
|
2020-07-20 06:50:05 +00:00
|
|
|
var pubkey = recover(sig, SkMessage(msgHash))
|
2020-04-05 13:12:48 +00:00
|
|
|
if pubkey.isErr:
|
2018-10-02 14:46:39 +00:00
|
|
|
raise newException(ValidationError, "Could not derive public key from computation")
|
2018-12-04 13:39:10 +00:00
|
|
|
|
2020-01-30 10:15:06 +00:00
|
|
|
computation.output.setLen(32)
|
2020-04-05 13:12:48 +00:00
|
|
|
computation.output[12..31] = pubkey[].toCanonicalAddress()
|
Tracing: Remove some trace messages that occur a lot during sync
Disable some trace messages which appeared a lot in the output and probably
aren't so useful any more, when block processing is functioning well at high
speed.
Turning on the trace level globally is useful to get a feel for what's
happening, but only if each category is kept to a reasonable amount.
As well as overwhelming the output so that it's hard to see general activity,
some of these messages happen so much they severely slow down processing. Ones
called every time an EVM opcode uses some gas are particularly extreme.
These messages have all been chosen as things which are probably not useful any
more (the relevant functionality has been debugged and is tested plenty).
These have been commented out rather than removed. It may be that turning
trace topics on/off, or other selection, is a better longer term solution, but
that will require better command line options and good defaults for sure.
(I think higher levels `tracev` and `tracevv` levels (extra verbose) would be
more useful for this sort of deep tracing on request.)
For now, enabling `--log-level:TRACE` on the command line is quite useful as
long as we keep each category reasonable, and this patch tries to keep that
balance.
- Don't show "has transactions" on virtually every block imported.
- Don't show "Sender" and "txHash" lines on every transaction processed.
- Don't show "GAS CONSUMPTION" on every opcode executed", this is way too much.
- Don't show "GAS RETURNED" and "GAS REFUND" on each contract call.
- Don't show "op: Stop" on every Stop opcode, which means every transaction.
- Don't show "Insufficient funds" whenever a contract can't call another.
- Don't show "ECRecover", "SHA256 precompile", "RIPEMD160", "Identity"
or even "Call precompile" every time a precompile is called. These are
very well tested now.
- Don't show "executeOpcodes error" whenever a contract returns an error.
(This is changed to `trace` too, it's a normal event that is well tested.)
Signed-off-by: Jamie Lokier <jamie@shareable.org>
2021-07-22 13:35:41 +00:00
|
|
|
#trace "ECRecover precompile", derivedKey = pubkey[].toCanonicalAddress()
|
2018-10-03 12:33:19 +00:00
|
|
|
|
2020-01-10 01:26:17 +00:00
|
|
|
proc sha256*(computation: Computation) =
|
2018-10-03 12:33:19 +00:00
|
|
|
let
|
2019-03-11 05:03:57 +00:00
|
|
|
wordCount = wordCount(computation.msg.data.len)
|
2018-10-03 16:59:41 +00:00
|
|
|
gasFee = GasSHA256 + wordCount * GasSHA256Word
|
2018-10-03 12:33:19 +00:00
|
|
|
|
|
|
|
computation.gasMeter.consumeGas(gasFee, reason="SHA256 Precompile")
|
2020-01-30 10:15:06 +00:00
|
|
|
computation.output = @(nimcrypto.sha_256.digest(computation.msg.data).data)
|
Tracing: Remove some trace messages that occur a lot during sync
Disable some trace messages which appeared a lot in the output and probably
aren't so useful any more, when block processing is functioning well at high
speed.
Turning on the trace level globally is useful to get a feel for what's
happening, but only if each category is kept to a reasonable amount.
As well as overwhelming the output so that it's hard to see general activity,
some of these messages happen so much they severely slow down processing. Ones
called every time an EVM opcode uses some gas are particularly extreme.
These messages have all been chosen as things which are probably not useful any
more (the relevant functionality has been debugged and is tested plenty).
These have been commented out rather than removed. It may be that turning
trace topics on/off, or other selection, is a better longer term solution, but
that will require better command line options and good defaults for sure.
(I think higher levels `tracev` and `tracevv` levels (extra verbose) would be
more useful for this sort of deep tracing on request.)
For now, enabling `--log-level:TRACE` on the command line is quite useful as
long as we keep each category reasonable, and this patch tries to keep that
balance.
- Don't show "has transactions" on virtually every block imported.
- Don't show "Sender" and "txHash" lines on every transaction processed.
- Don't show "GAS CONSUMPTION" on every opcode executed", this is way too much.
- Don't show "GAS RETURNED" and "GAS REFUND" on each contract call.
- Don't show "op: Stop" on every Stop opcode, which means every transaction.
- Don't show "Insufficient funds" whenever a contract can't call another.
- Don't show "ECRecover", "SHA256 precompile", "RIPEMD160", "Identity"
or even "Call precompile" every time a precompile is called. These are
very well tested now.
- Don't show "executeOpcodes error" whenever a contract returns an error.
(This is changed to `trace` too, it's a normal event that is well tested.)
Signed-off-by: Jamie Lokier <jamie@shareable.org>
2021-07-22 13:35:41 +00:00
|
|
|
#trace "SHA256 precompile", output = computation.output.toHex
|
2018-10-03 12:33:19 +00:00
|
|
|
|
2020-01-10 01:26:17 +00:00
|
|
|
proc ripemd160*(computation: Computation) =
|
2018-10-03 12:33:19 +00:00
|
|
|
let
|
2019-03-11 05:03:57 +00:00
|
|
|
wordCount = wordCount(computation.msg.data.len)
|
2018-10-03 16:59:41 +00:00
|
|
|
gasFee = GasRIPEMD160 + wordCount * GasRIPEMD160Word
|
2018-10-03 12:33:19 +00:00
|
|
|
|
|
|
|
computation.gasMeter.consumeGas(gasFee, reason="RIPEMD160 Precompile")
|
2020-01-30 10:15:06 +00:00
|
|
|
computation.output.setLen(32)
|
|
|
|
computation.output[12..31] = @(nimcrypto.ripemd160.digest(computation.msg.data).data)
|
Tracing: Remove some trace messages that occur a lot during sync
Disable some trace messages which appeared a lot in the output and probably
aren't so useful any more, when block processing is functioning well at high
speed.
Turning on the trace level globally is useful to get a feel for what's
happening, but only if each category is kept to a reasonable amount.
As well as overwhelming the output so that it's hard to see general activity,
some of these messages happen so much they severely slow down processing. Ones
called every time an EVM opcode uses some gas are particularly extreme.
These messages have all been chosen as things which are probably not useful any
more (the relevant functionality has been debugged and is tested plenty).
These have been commented out rather than removed. It may be that turning
trace topics on/off, or other selection, is a better longer term solution, but
that will require better command line options and good defaults for sure.
(I think higher levels `tracev` and `tracevv` levels (extra verbose) would be
more useful for this sort of deep tracing on request.)
For now, enabling `--log-level:TRACE` on the command line is quite useful as
long as we keep each category reasonable, and this patch tries to keep that
balance.
- Don't show "has transactions" on virtually every block imported.
- Don't show "Sender" and "txHash" lines on every transaction processed.
- Don't show "GAS CONSUMPTION" on every opcode executed", this is way too much.
- Don't show "GAS RETURNED" and "GAS REFUND" on each contract call.
- Don't show "op: Stop" on every Stop opcode, which means every transaction.
- Don't show "Insufficient funds" whenever a contract can't call another.
- Don't show "ECRecover", "SHA256 precompile", "RIPEMD160", "Identity"
or even "Call precompile" every time a precompile is called. These are
very well tested now.
- Don't show "executeOpcodes error" whenever a contract returns an error.
(This is changed to `trace` too, it's a normal event that is well tested.)
Signed-off-by: Jamie Lokier <jamie@shareable.org>
2021-07-22 13:35:41 +00:00
|
|
|
#trace "RIPEMD160 precompile", output = computation.output.toHex
|
2018-10-03 12:33:19 +00:00
|
|
|
|
2020-01-10 01:26:17 +00:00
|
|
|
proc identity*(computation: Computation) =
|
2018-10-03 12:33:19 +00:00
|
|
|
let
|
2019-02-14 14:47:22 +00:00
|
|
|
wordCount = wordCount(computation.msg.data.len)
|
2018-10-03 16:59:41 +00:00
|
|
|
gasFee = GasIdentity + wordCount * GasIdentityWord
|
2018-10-03 12:33:19 +00:00
|
|
|
|
2018-10-03 16:59:41 +00:00
|
|
|
computation.gasMeter.consumeGas(gasFee, reason="Identity Precompile")
|
2020-01-30 10:15:06 +00:00
|
|
|
computation.output = computation.msg.data
|
Tracing: Remove some trace messages that occur a lot during sync
Disable some trace messages which appeared a lot in the output and probably
aren't so useful any more, when block processing is functioning well at high
speed.
Turning on the trace level globally is useful to get a feel for what's
happening, but only if each category is kept to a reasonable amount.
As well as overwhelming the output so that it's hard to see general activity,
some of these messages happen so much they severely slow down processing. Ones
called every time an EVM opcode uses some gas are particularly extreme.
These messages have all been chosen as things which are probably not useful any
more (the relevant functionality has been debugged and is tested plenty).
These have been commented out rather than removed. It may be that turning
trace topics on/off, or other selection, is a better longer term solution, but
that will require better command line options and good defaults for sure.
(I think higher levels `tracev` and `tracevv` levels (extra verbose) would be
more useful for this sort of deep tracing on request.)
For now, enabling `--log-level:TRACE` on the command line is quite useful as
long as we keep each category reasonable, and this patch tries to keep that
balance.
- Don't show "has transactions" on virtually every block imported.
- Don't show "Sender" and "txHash" lines on every transaction processed.
- Don't show "GAS CONSUMPTION" on every opcode executed", this is way too much.
- Don't show "GAS RETURNED" and "GAS REFUND" on each contract call.
- Don't show "op: Stop" on every Stop opcode, which means every transaction.
- Don't show "Insufficient funds" whenever a contract can't call another.
- Don't show "ECRecover", "SHA256 precompile", "RIPEMD160", "Identity"
or even "Call precompile" every time a precompile is called. These are
very well tested now.
- Don't show "executeOpcodes error" whenever a contract returns an error.
(This is changed to `trace` too, it's a normal event that is well tested.)
Signed-off-by: Jamie Lokier <jamie@shareable.org>
2021-07-22 13:35:41 +00:00
|
|
|
#trace "Identity precompile", output = computation.output.toHex
|
2018-10-02 14:46:39 +00:00
|
|
|
|
2020-02-11 02:28:34 +00:00
|
|
|
proc modExpInternal(computation: Computation, baseLen, expLen, modLen: int, T: type StUint) =
|
|
|
|
template data: untyped {.dirty.} =
|
2018-10-05 15:26:20 +00:00
|
|
|
computation.msg.data
|
|
|
|
|
2020-02-11 02:28:34 +00:00
|
|
|
let
|
|
|
|
base = data.rangeToPadded[:T](96, 95 + baseLen, baseLen)
|
|
|
|
exp = data.rangeToPadded[:T](96 + baseLen, 95 + baseLen + expLen, expLen)
|
|
|
|
modulo = data.rangeToPadded[:T](96 + baseLen + expLen, 95 + baseLen + expLen + modLen, modLen)
|
|
|
|
|
|
|
|
# TODO: specs mentions that we should return in "M" format
|
|
|
|
# i.e. if Base and exp are uint512 and Modulo an uint256
|
|
|
|
# we should return a 256-bit big-endian byte array
|
|
|
|
|
|
|
|
# Force static evaluation
|
|
|
|
func zero(): array[T.bits div 8, byte] {.compileTime.} = discard
|
|
|
|
func one(): array[T.bits div 8, byte] {.compileTime.} =
|
|
|
|
when cpuEndian == bigEndian:
|
|
|
|
result[0] = 1
|
|
|
|
else:
|
|
|
|
result[^1] = 1
|
|
|
|
|
|
|
|
# Start with EVM special cases
|
|
|
|
let output = if modulo <= 1:
|
|
|
|
# If m == 0: EVM returns 0.
|
|
|
|
# If m == 1: we can shortcut that to 0 as well
|
|
|
|
zero()
|
|
|
|
elif exp.isZero():
|
|
|
|
# If 0^0: EVM returns 1
|
|
|
|
# For all x != 0, x^0 == 1 as well
|
|
|
|
one()
|
|
|
|
else:
|
|
|
|
powmod(base, exp, modulo).toByteArrayBE
|
|
|
|
|
|
|
|
# maximum output len is the same as modLen
|
|
|
|
# if it less than modLen, it will be zero padded at left
|
|
|
|
if output.len >= modLen:
|
|
|
|
computation.output = @(output[^modLen..^1])
|
|
|
|
else:
|
|
|
|
computation.output = newSeq[byte](modLen)
|
|
|
|
computation.output[^output.len..^1] = output[0..^1]
|
2018-10-05 15:26:20 +00:00
|
|
|
|
2020-11-24 09:19:02 +00:00
|
|
|
proc modExpFee(c: Computation, baseLen, expLen, modLen: Uint256, fork: Fork): GasInt =
|
2020-02-11 02:28:34 +00:00
|
|
|
template data: untyped {.dirty.} =
|
|
|
|
c.msg.data
|
2018-10-05 15:26:20 +00:00
|
|
|
|
2020-11-24 09:19:02 +00:00
|
|
|
func mulComplexity(x: Uint256): Uint256 =
|
2020-02-11 02:28:34 +00:00
|
|
|
## Estimates the difficulty of Karatsuba multiplication
|
|
|
|
if x <= 64.u256: x * x
|
|
|
|
elif x <= 1024.u256: x * x div 4.u256 + 96.u256 * x - 3072.u256
|
|
|
|
else: x * x div 16.u256 + 480.u256 * x - 199680.u256
|
2018-12-04 14:52:59 +00:00
|
|
|
|
2020-11-24 09:19:02 +00:00
|
|
|
func mulComplexityEIP2565(x: Uint256): Uint256 =
|
|
|
|
# gas = ceil(x div 8) ^ 2
|
|
|
|
result = x + 7
|
|
|
|
result = result div 8
|
|
|
|
result = result * result
|
|
|
|
|
2020-02-11 02:28:34 +00:00
|
|
|
let adjExpLen = block:
|
2019-05-09 01:56:10 +00:00
|
|
|
let
|
2020-02-11 02:28:34 +00:00
|
|
|
baseL = baseLen.safeInt
|
|
|
|
expL = expLen.safeInt
|
|
|
|
first32 = if baseL.uint64 + expL.uint64 < high(int32).uint64 and baseL < data.len:
|
|
|
|
data.rangeToPadded2[:Uint256](96 + baseL, 95 + baseL + expL, min(expL, 32))
|
2019-05-09 01:56:10 +00:00
|
|
|
else:
|
2020-02-11 02:28:34 +00:00
|
|
|
0.u256
|
2019-04-24 15:37:34 +00:00
|
|
|
|
2020-02-11 02:28:34 +00:00
|
|
|
if expLen <= 32:
|
|
|
|
if first32.isZero(): 0.u256
|
|
|
|
else: first32.log2.u256 # highest-bit in exponent
|
2018-10-05 15:26:20 +00:00
|
|
|
else:
|
2020-02-11 02:28:34 +00:00
|
|
|
if not first32.isZero:
|
|
|
|
8.u256 * (expLen - 32.u256) + first32.log2.u256
|
|
|
|
else:
|
|
|
|
8.u256 * (expLen - 32.u256)
|
|
|
|
|
2020-11-24 09:19:02 +00:00
|
|
|
template gasCalc(comp, divisor: untyped): untyped =
|
|
|
|
(
|
|
|
|
max(modLen, baseLen).comp *
|
|
|
|
max(adjExpLen, 1.u256)
|
|
|
|
) div divisor
|
|
|
|
|
2021-05-16 12:22:01 +00:00
|
|
|
# EIP2565: modExp gas cost
|
|
|
|
let gasFee = if fork >= FkBerlin: gasCalc(mulComplexityEIP2565, GasQuadDivisorEIP2565)
|
|
|
|
else: gasCalc(mulComplexity, GasQuadDivisor)
|
2021-01-11 07:53:51 +00:00
|
|
|
|
2021-05-16 12:22:01 +00:00
|
|
|
#let gasFee = gasCalc(mulComplexity, GasQuadDivisor)
|
2020-02-11 02:28:34 +00:00
|
|
|
|
|
|
|
if gasFee > high(GasInt).u256:
|
|
|
|
raise newException(OutOfGas, "modExp gas overflow")
|
|
|
|
|
|
|
|
result = gasFee.truncate(GasInt)
|
2021-01-11 08:33:30 +00:00
|
|
|
|
2021-05-16 12:22:01 +00:00
|
|
|
# EIP2565: modExp gas cost
|
|
|
|
if fork >= FkBerlin and result < 200.GasInt:
|
|
|
|
result = 200.GasInt
|
2018-10-05 15:26:20 +00:00
|
|
|
|
2020-11-24 09:19:02 +00:00
|
|
|
proc modExp*(c: Computation, fork: Fork = FkByzantium) =
|
2018-12-04 13:39:10 +00:00
|
|
|
## Modular exponentiation precompiled contract
|
|
|
|
## Yellow Paper Appendix E
|
|
|
|
## EIP-198 - https://github.com/ethereum/EIPs/blob/master/EIPS/eip-198.md
|
|
|
|
# Parsing the data
|
2020-02-11 02:28:34 +00:00
|
|
|
template data: untyped {.dirty.} =
|
2020-11-24 09:19:02 +00:00
|
|
|
c.msg.data
|
2019-05-09 01:56:10 +00:00
|
|
|
|
2018-12-04 13:39:10 +00:00
|
|
|
let # lengths Base, Exponent, Modulus
|
2020-02-11 02:28:34 +00:00
|
|
|
baseL = data.rangeToPadded[:Uint256](0, 31)
|
|
|
|
expL = data.rangeToPadded[:Uint256](32, 63)
|
|
|
|
modL = data.rangeToPadded[:Uint256](64, 95)
|
|
|
|
baseLen = baseL.safeInt
|
|
|
|
expLen = expL.safeInt
|
|
|
|
modLen = modL.safeInt
|
|
|
|
|
2020-11-24 09:19:02 +00:00
|
|
|
let gasFee = modExpFee(c, baseL, expL, modL, fork)
|
|
|
|
c.gasMeter.consumeGas(gasFee, reason="ModExp Precompile")
|
2020-02-11 02:28:34 +00:00
|
|
|
|
|
|
|
if baseLen == 0 and modLen == 0:
|
|
|
|
# This is a special case where expLength can be very big.
|
2020-11-24 09:19:02 +00:00
|
|
|
c.output = @[]
|
2020-02-11 02:28:34 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
let maxBytes = max(baseLen, max(expLen, modLen))
|
2018-12-04 13:39:10 +00:00
|
|
|
if maxBytes <= 32:
|
2020-11-24 09:19:02 +00:00
|
|
|
c.modExpInternal(baseLen, expLen, modLen, UInt256)
|
2018-12-04 13:39:10 +00:00
|
|
|
elif maxBytes <= 64:
|
2020-11-24 09:19:02 +00:00
|
|
|
c.modExpInternal(baseLen, expLen, modLen, StUint[512])
|
2018-12-04 13:39:10 +00:00
|
|
|
elif maxBytes <= 128:
|
2020-11-24 09:19:02 +00:00
|
|
|
c.modExpInternal(baseLen, expLen, modLen, StUint[1024])
|
2018-12-04 13:39:10 +00:00
|
|
|
elif maxBytes <= 256:
|
2020-11-24 09:19:02 +00:00
|
|
|
c.modExpInternal(baseLen, expLen, modLen, StUint[2048])
|
2018-12-04 13:39:10 +00:00
|
|
|
elif maxBytes <= 512:
|
2020-11-24 09:19:02 +00:00
|
|
|
c.modExpInternal(baseLen, expLen, modLen, StUint[4096])
|
2018-12-04 14:46:33 +00:00
|
|
|
elif maxBytes <= 1024:
|
2020-11-24 09:19:02 +00:00
|
|
|
c.modExpInternal(baseLen, expLen, modLen, StUint[8192])
|
2018-12-04 13:39:10 +00:00
|
|
|
else:
|
2019-07-19 09:39:54 +00:00
|
|
|
raise newException(EVMError, "The Nimbus VM doesn't support modular exponentiation with numbers larger than uint8192")
|
2018-12-04 13:39:10 +00:00
|
|
|
|
2020-01-10 01:26:17 +00:00
|
|
|
proc bn256ecAdd*(computation: Computation, fork: Fork = FkByzantium) =
|
2019-11-11 04:33:56 +00:00
|
|
|
let gasFee = if fork < FkIstanbul: GasECAdd else: GasECAddIstanbul
|
|
|
|
computation.gasMeter.consumeGas(gasFee, reason = "ecAdd Precompile")
|
2019-04-24 05:56:10 +00:00
|
|
|
|
2018-10-05 09:15:04 +00:00
|
|
|
var
|
|
|
|
input: array[128, byte]
|
|
|
|
output: array[64, byte]
|
|
|
|
# Padding data
|
2020-02-06 04:37:44 +00:00
|
|
|
let len = min(computation.msg.data.len, 128) - 1
|
|
|
|
input[0..len] = computation.msg.data[0..len]
|
2018-10-05 09:15:04 +00:00
|
|
|
var p1 = G1.getPoint(input.toOpenArray(0, 63))
|
|
|
|
var p2 = G1.getPoint(input.toOpenArray(64, 127))
|
|
|
|
var apo = (p1 + p2).toAffine()
|
|
|
|
if isSome(apo):
|
|
|
|
# we can discard here because we supply proper buffer
|
2018-10-16 08:49:13 +00:00
|
|
|
discard apo.get().toBytes(output)
|
2018-10-05 09:15:04 +00:00
|
|
|
|
2020-01-30 10:15:06 +00:00
|
|
|
computation.output = @output
|
2018-10-05 09:15:04 +00:00
|
|
|
|
2020-01-10 01:26:17 +00:00
|
|
|
proc bn256ecMul*(computation: Computation, fork: Fork = FkByzantium) =
|
2019-11-11 04:33:56 +00:00
|
|
|
let gasFee = if fork < FkIstanbul: GasECMul else: GasECMulIstanbul
|
|
|
|
computation.gasMeter.consumeGas(gasFee, reason="ecMul Precompile")
|
2019-04-24 05:56:10 +00:00
|
|
|
|
2018-10-05 09:15:04 +00:00
|
|
|
var
|
|
|
|
input: array[96, byte]
|
|
|
|
output: array[64, byte]
|
|
|
|
|
|
|
|
# Padding data
|
2020-02-06 04:37:44 +00:00
|
|
|
let len = min(computation.msg.data.len, 96) - 1
|
|
|
|
input[0..len] = computation.msg.data[0..len]
|
2018-10-05 09:15:04 +00:00
|
|
|
var p1 = G1.getPoint(input.toOpenArray(0, 63))
|
|
|
|
var fr = getFR(input.toOpenArray(64, 95))
|
|
|
|
var apo = (p1 * fr).toAffine()
|
|
|
|
if isSome(apo):
|
|
|
|
# we can discard here because we supply buffer of proper size
|
2018-10-16 08:49:13 +00:00
|
|
|
discard apo.get().toBytes(output)
|
2018-10-05 09:15:04 +00:00
|
|
|
|
2020-01-30 10:15:06 +00:00
|
|
|
computation.output = @output
|
2018-10-05 09:15:04 +00:00
|
|
|
|
2020-01-10 01:26:17 +00:00
|
|
|
proc bn256ecPairing*(computation: Computation, fork: Fork = FkByzantium) =
|
2018-10-05 09:15:04 +00:00
|
|
|
let msglen = len(computation.msg.data)
|
|
|
|
if msglen mod 192 != 0:
|
|
|
|
raise newException(ValidationError, "Invalid input length")
|
|
|
|
|
2019-04-24 05:56:10 +00:00
|
|
|
let numPoints = msglen div 192
|
2019-11-11 04:33:56 +00:00
|
|
|
let gasFee = if fork < FkIstanbul:
|
|
|
|
GasECPairingBase + numPoints * GasECPairingPerPoint
|
|
|
|
else:
|
|
|
|
GasECPairingBaseIstanbul + numPoints * GasECPairingPerPointIstanbul
|
2019-04-24 05:56:10 +00:00
|
|
|
computation.gasMeter.consumeGas(gasFee, reason="ecPairing Precompile")
|
|
|
|
|
|
|
|
var output: array[32, byte]
|
2018-10-05 09:15:04 +00:00
|
|
|
if msglen == 0:
|
|
|
|
# we can discard here because we supply buffer of proper size
|
|
|
|
discard BNU256.one().toBytes(output)
|
|
|
|
else:
|
|
|
|
# Calculate number of pairing pairs
|
|
|
|
let count = msglen div 192
|
|
|
|
# Pairing accumulator
|
|
|
|
var acc = FQ12.one()
|
|
|
|
|
|
|
|
for i in 0..<count:
|
|
|
|
let s = i * 192
|
|
|
|
# Loading AffinePoint[G1], bytes from [0..63]
|
|
|
|
var p1 = G1.getPoint(computation.msg.data.toOpenArray(s, s + 63))
|
|
|
|
# Loading AffinePoint[G2], bytes from [64..191]
|
|
|
|
var p2 = G2.getPoint(computation.msg.data.toOpenArray(s + 64, s + 191))
|
|
|
|
# Accumulate pairing result
|
|
|
|
acc = acc * pairing(p1, p2)
|
|
|
|
|
|
|
|
if acc == FQ12.one():
|
|
|
|
# we can discard here because we supply buffer of proper size
|
|
|
|
discard BNU256.one().toBytes(output)
|
|
|
|
|
2020-01-30 10:15:06 +00:00
|
|
|
computation.output = @output
|
2018-10-05 09:15:04 +00:00
|
|
|
|
2020-11-27 14:42:17 +00:00
|
|
|
proc blake2bf*(c: Computation) =
|
|
|
|
template input: untyped =
|
|
|
|
c.msg.data
|
2019-11-11 04:21:16 +00:00
|
|
|
|
|
|
|
if len(input) == blake2FInputLength:
|
|
|
|
let gasFee = GasInt(beLoad32(input, 0))
|
2020-11-27 14:42:17 +00:00
|
|
|
c.gasMeter.consumeGas(gasFee, reason="blake2bf Precompile")
|
2019-11-11 04:21:16 +00:00
|
|
|
|
|
|
|
var output: array[64, byte]
|
|
|
|
if not blake2b_F(input, output):
|
|
|
|
raise newException(ValidationError, "Blake2b F function invalid input")
|
|
|
|
else:
|
2020-11-27 14:42:17 +00:00
|
|
|
c.output = @output
|
|
|
|
|
|
|
|
proc blsG1Add*(c: Computation) =
|
|
|
|
template input: untyped =
|
|
|
|
c.msg.data
|
|
|
|
|
|
|
|
if input.len != 256:
|
|
|
|
raise newException(ValidationError, "blsG1Add invalid input len")
|
|
|
|
|
|
|
|
c.gasMeter.consumeGas(Bls12381G1AddGas, reason="blsG1Add Precompile")
|
|
|
|
|
|
|
|
var a, b: BLS_G1
|
|
|
|
if not a.decodePoint(input.toOpenArray(0, 127)):
|
|
|
|
raise newException(ValidationError, "blsG1Add invalid input A")
|
|
|
|
|
|
|
|
if not b.decodePoint(input.toOpenArray(128, 255)):
|
|
|
|
raise newException(ValidationError, "blsG1Add invalid input B")
|
|
|
|
|
|
|
|
a.add b
|
|
|
|
|
|
|
|
c.output = newSeq[byte](128)
|
|
|
|
if not encodePoint(a, c.output):
|
|
|
|
raise newException(ValidationError, "blsG1Add encodePoint error")
|
|
|
|
|
|
|
|
proc blsG1Mul*(c: Computation) =
|
|
|
|
template input: untyped =
|
|
|
|
c.msg.data
|
|
|
|
|
|
|
|
if input.len != 160:
|
|
|
|
raise newException(ValidationError, "blsG1Mul invalid input len")
|
|
|
|
|
|
|
|
c.gasMeter.consumeGas(Bls12381G1MulGas, reason="blsG1Mul Precompile")
|
|
|
|
|
|
|
|
var a: BLS_G1
|
|
|
|
if not a.decodePoint(input.toOpenArray(0, 127)):
|
|
|
|
raise newException(ValidationError, "blsG1Mul invalid input A")
|
|
|
|
|
|
|
|
var scalar: BLS_SCALAR
|
|
|
|
if not scalar.fromBytes(input.toOpenArray(128, 159)):
|
|
|
|
raise newException(ValidationError, "blsG1Mul invalid scalar")
|
|
|
|
|
|
|
|
a.mul(scalar)
|
|
|
|
|
|
|
|
c.output = newSeq[byte](128)
|
|
|
|
if not encodePoint(a, c.output):
|
|
|
|
raise newException(ValidationError, "blsG1Mul encodePoint error")
|
|
|
|
|
|
|
|
const
|
|
|
|
Bls12381MultiExpDiscountTable = [
|
|
|
|
1200, 888, 764, 641, 594, 547, 500, 453, 438, 423,
|
|
|
|
408, 394, 379, 364, 349, 334, 330, 326, 322, 318,
|
|
|
|
314, 310, 306, 302, 298, 294, 289, 285, 281, 277,
|
|
|
|
273, 269, 268, 266, 265, 263, 262, 260, 259, 257,
|
|
|
|
256, 254, 253, 251, 250, 248, 247, 245, 244, 242,
|
|
|
|
241, 239, 238, 236, 235, 233, 232, 231, 229, 228,
|
|
|
|
226, 225, 223, 222, 221, 220, 219, 219, 218, 217,
|
|
|
|
216, 216, 215, 214, 213, 213, 212, 211, 211, 210,
|
|
|
|
209, 208, 208, 207, 206, 205, 205, 204, 203, 202,
|
|
|
|
202, 201, 200, 199, 199, 198, 197, 196, 196, 195,
|
|
|
|
194, 193, 193, 192, 191, 191, 190, 189, 188, 188,
|
|
|
|
187, 186, 185, 185, 184, 183, 182, 182, 181, 180,
|
|
|
|
179, 179, 178, 177, 176, 176, 175, 174
|
|
|
|
]
|
|
|
|
|
|
|
|
func calcBlsMultiExpGas(K: int, gasCost: GasInt): GasInt =
|
|
|
|
# Calculate G1 point, scalar value pair length
|
|
|
|
if K == 0:
|
|
|
|
# Return 0 gas for small input length
|
|
|
|
return 0.GasInt
|
|
|
|
|
|
|
|
const dLen = Bls12381MultiExpDiscountTable.len
|
|
|
|
# Lookup discount value for G1 point, scalar value pair length
|
|
|
|
let discount = if K < dLen: Bls12381MultiExpDiscountTable[K-1]
|
|
|
|
else: Bls12381MultiExpDiscountTable[dLen-1]
|
|
|
|
|
|
|
|
# Calculate gas and return the result
|
|
|
|
result = (K * gasCost * discount) div 1000
|
|
|
|
|
|
|
|
proc blsG1MultiExp*(c: Computation) =
|
|
|
|
template input: untyped =
|
|
|
|
c.msg.data
|
|
|
|
|
|
|
|
const L = 160
|
|
|
|
if (input.len == 0) or ((input.len mod L) != 0):
|
|
|
|
raise newException(ValidationError, "blsG1MultiExp invalid input len")
|
|
|
|
|
|
|
|
let
|
|
|
|
K = input.len div L
|
|
|
|
gas = K.calcBlsMultiExpGas(Bls12381G1MulGas)
|
|
|
|
|
|
|
|
c.gasMeter.consumeGas(gas, reason="blsG1MultiExp Precompile")
|
|
|
|
|
|
|
|
var
|
|
|
|
p: BLS_G1
|
|
|
|
s: BLS_SCALAR
|
|
|
|
acc: BLS_G1
|
|
|
|
|
|
|
|
# Decode point scalar pairs
|
|
|
|
for i in 0..<K:
|
|
|
|
let off = L * i
|
|
|
|
|
|
|
|
# Decode G1 point
|
|
|
|
if not p.decodePoint(input.toOpenArray(off, off+127)):
|
|
|
|
raise newException(ValidationError, "blsG1MultiExp invalid input P")
|
|
|
|
|
|
|
|
# Decode scalar value
|
|
|
|
if not s.fromBytes(input.toOpenArray(off+128, off+159)):
|
|
|
|
raise newException(ValidationError, "blsG1MultiExp invalid scalar")
|
|
|
|
|
|
|
|
p.mul(s)
|
|
|
|
if i == 0:
|
|
|
|
acc = p
|
|
|
|
else:
|
|
|
|
acc.add(p)
|
|
|
|
|
|
|
|
c.output = newSeq[byte](128)
|
|
|
|
if not encodePoint(acc, c.output):
|
|
|
|
raise newException(ValidationError, "blsG1MuliExp encodePoint error")
|
|
|
|
|
|
|
|
proc blsG2Add*(c: Computation) =
|
|
|
|
template input: untyped =
|
|
|
|
c.msg.data
|
|
|
|
|
|
|
|
if input.len != 512:
|
|
|
|
raise newException(ValidationError, "blsG2Add invalid input len")
|
|
|
|
|
|
|
|
c.gasMeter.consumeGas(Bls12381G2AddGas, reason="blsG2Add Precompile")
|
|
|
|
|
|
|
|
var a, b: BLS_G2
|
|
|
|
if not a.decodePoint(input.toOpenArray(0, 255)):
|
|
|
|
raise newException(ValidationError, "blsG2Add invalid input A")
|
|
|
|
|
|
|
|
if not b.decodePoint(input.toOpenArray(256, 511)):
|
|
|
|
raise newException(ValidationError, "blsG2Add invalid input B")
|
|
|
|
|
|
|
|
a.add b
|
|
|
|
|
|
|
|
c.output = newSeq[byte](256)
|
|
|
|
if not encodePoint(a, c.output):
|
|
|
|
raise newException(ValidationError, "blsG2Add encodePoint error")
|
|
|
|
|
|
|
|
proc blsG2Mul*(c: Computation) =
|
|
|
|
template input: untyped =
|
|
|
|
c.msg.data
|
|
|
|
|
|
|
|
if input.len != 288:
|
|
|
|
raise newException(ValidationError, "blsG2Mul invalid input len")
|
|
|
|
|
|
|
|
c.gasMeter.consumeGas(Bls12381G2MulGas, reason="blsG2Mul Precompile")
|
|
|
|
|
|
|
|
var a: BLS_G2
|
|
|
|
if not a.decodePoint(input.toOpenArray(0, 255)):
|
|
|
|
raise newException(ValidationError, "blsG2Mul invalid input A")
|
|
|
|
|
|
|
|
var scalar: BLS_SCALAR
|
|
|
|
if not scalar.fromBytes(input.toOpenArray(256, 287)):
|
|
|
|
raise newException(ValidationError, "blsG2Mul invalid scalar")
|
|
|
|
|
|
|
|
a.mul(scalar)
|
|
|
|
|
|
|
|
c.output = newSeq[byte](256)
|
|
|
|
if not encodePoint(a, c.output):
|
|
|
|
raise newException(ValidationError, "blsG2Mul encodePoint error")
|
|
|
|
|
|
|
|
proc blsG2MultiExp*(c: Computation) =
|
|
|
|
template input: untyped =
|
|
|
|
c.msg.data
|
|
|
|
|
|
|
|
const L = 288
|
|
|
|
if (input.len == 0) or ((input.len mod L) != 0):
|
|
|
|
raise newException(ValidationError, "blsG2MultiExp invalid input len")
|
|
|
|
|
|
|
|
let
|
|
|
|
K = input.len div L
|
|
|
|
gas = K.calcBlsMultiExpGas(Bls12381G2MulGas)
|
|
|
|
|
|
|
|
c.gasMeter.consumeGas(gas, reason="blsG2MultiExp Precompile")
|
|
|
|
|
|
|
|
var
|
|
|
|
p: BLS_G2
|
|
|
|
s: BLS_SCALAR
|
|
|
|
acc: BLS_G2
|
|
|
|
|
|
|
|
# Decode point scalar pairs
|
|
|
|
for i in 0..<K:
|
|
|
|
let off = L * i
|
|
|
|
|
|
|
|
# Decode G1 point
|
|
|
|
if not p.decodePoint(input.toOpenArray(off, off+255)):
|
|
|
|
raise newException(ValidationError, "blsG2MultiExp invalid input P")
|
|
|
|
|
|
|
|
# Decode scalar value
|
|
|
|
if not s.fromBytes(input.toOpenArray(off+256, off+287)):
|
|
|
|
raise newException(ValidationError, "blsG2MultiExp invalid scalar")
|
|
|
|
|
|
|
|
p.mul(s)
|
|
|
|
if i == 0:
|
|
|
|
acc = p
|
|
|
|
else:
|
|
|
|
acc.add(p)
|
|
|
|
|
|
|
|
c.output = newSeq[byte](256)
|
|
|
|
if not encodePoint(acc, c.output):
|
|
|
|
raise newException(ValidationError, "blsG2MuliExp encodePoint error")
|
|
|
|
|
|
|
|
proc blsPairing*(c: Computation) =
|
2020-11-28 16:13:10 +00:00
|
|
|
template input: untyped =
|
|
|
|
c.msg.data
|
|
|
|
|
|
|
|
const L = 384
|
|
|
|
if (input.len == 0) or ((input.len mod L) != 0):
|
|
|
|
raise newException(ValidationError, "blsG2Pairing invalid input len")
|
|
|
|
|
|
|
|
let
|
|
|
|
K = input.len div L
|
|
|
|
gas = Bls12381PairingBaseGas + K.GasInt * Bls12381PairingPerPairGas
|
|
|
|
|
|
|
|
c.gasMeter.consumeGas(gas, reason="blsG2Pairing Precompile")
|
|
|
|
|
|
|
|
var
|
2020-12-02 07:03:40 +00:00
|
|
|
g1: BLS_G1P
|
|
|
|
g2: BLS_G2P
|
|
|
|
acc: BLS_ACC
|
2020-11-28 16:13:10 +00:00
|
|
|
|
|
|
|
# Decode pairs
|
|
|
|
for i in 0..<K:
|
|
|
|
let off = L * i
|
|
|
|
|
|
|
|
# Decode G1 point
|
|
|
|
if not g1.decodePoint(input.toOpenArray(off, off+127)):
|
|
|
|
raise newException(ValidationError, "blsG2Pairing invalid G1")
|
|
|
|
|
|
|
|
# Decode G2 point
|
|
|
|
if not g2.decodePoint(input.toOpenArray(off+128, off+383)):
|
|
|
|
raise newException(ValidationError, "blsG2Pairing invalid G2")
|
|
|
|
|
|
|
|
# 'point is on curve' check already done,
|
|
|
|
# Here we need to apply subgroup checks.
|
|
|
|
if not g1.subgroupCheck:
|
|
|
|
raise newException(ValidationError, "blsG2Pairing invalid G1 subgroup")
|
|
|
|
|
|
|
|
if not g2.subgroupCheck:
|
|
|
|
raise newException(ValidationError, "blsG2Pairing invalid G2 subgroup")
|
|
|
|
|
|
|
|
# Update pairing engine with G1 and G2 points
|
|
|
|
if i == 0:
|
2020-12-02 07:03:40 +00:00
|
|
|
acc = millerLoop(g1, g2)
|
2020-11-28 16:13:10 +00:00
|
|
|
else:
|
2020-12-02 07:03:40 +00:00
|
|
|
acc.mul(millerLoop(g1, g2))
|
2020-11-28 16:13:10 +00:00
|
|
|
|
|
|
|
c.output = newSeq[byte](32)
|
2020-12-02 07:03:40 +00:00
|
|
|
if acc.check():
|
2020-11-28 16:13:10 +00:00
|
|
|
c.output[^1] = 1.byte
|
2020-11-27 14:42:17 +00:00
|
|
|
|
|
|
|
proc blsMapG1*(c: Computation) =
|
2020-11-28 16:13:10 +00:00
|
|
|
template input: untyped =
|
|
|
|
c.msg.data
|
|
|
|
|
|
|
|
if input.len != 64:
|
|
|
|
raise newException(ValidationError, "blsMapG1 invalid input len")
|
|
|
|
|
|
|
|
c.gasMeter.consumeGas(Bls12381MapG1Gas, reason="blsMapG1 Precompile")
|
|
|
|
|
|
|
|
var fe: BLS_FE
|
2020-11-29 01:01:17 +00:00
|
|
|
if not fe.decodeFE(input):
|
2020-11-28 16:13:10 +00:00
|
|
|
raise newException(ValidationError, "blsMapG1 invalid field element")
|
|
|
|
|
|
|
|
let p = fe.mapFPToG1()
|
|
|
|
|
|
|
|
c.output = newSeq[byte](128)
|
|
|
|
if not encodePoint(p, c.output):
|
|
|
|
raise newException(ValidationError, "blsMapG1 encodePoint error")
|
2020-11-27 14:42:17 +00:00
|
|
|
|
|
|
|
proc blsMapG2*(c: Computation) =
|
2020-11-28 16:13:10 +00:00
|
|
|
template input: untyped =
|
|
|
|
c.msg.data
|
|
|
|
|
|
|
|
if input.len != 128:
|
|
|
|
raise newException(ValidationError, "blsMapG2 invalid input len")
|
|
|
|
|
|
|
|
c.gasMeter.consumeGas(Bls12381MapG2Gas, reason="blsMapG2 Precompile")
|
|
|
|
|
|
|
|
var fe: BLS_FE2
|
2020-11-29 01:01:17 +00:00
|
|
|
if not fe.decodeFE(input):
|
2020-11-28 16:13:10 +00:00
|
|
|
raise newException(ValidationError, "blsMapG2 invalid field element")
|
|
|
|
|
|
|
|
let p = fe.mapFPToG2()
|
|
|
|
|
|
|
|
c.output = newSeq[byte](256)
|
|
|
|
if not encodePoint(p, c.output):
|
|
|
|
raise newException(ValidationError, "blsMapG2 encodePoint error")
|
2019-11-11 04:21:16 +00:00
|
|
|
|
|
|
|
proc getMaxPrecompileAddr(fork: Fork): PrecompileAddresses =
|
|
|
|
if fork < FkByzantium: paIdentity
|
|
|
|
elif fork < FkIstanbul: paPairing
|
2021-05-16 12:44:24 +00:00
|
|
|
# EIP 2537: disabled
|
|
|
|
# reason: not included in berlin
|
|
|
|
# elif fork < FkBerlin: paBlake2bf
|
2019-11-11 04:21:16 +00:00
|
|
|
else: PrecompileAddresses.high
|
|
|
|
|
2020-01-10 01:26:17 +00:00
|
|
|
proc execPrecompiles*(computation: Computation, fork: Fork): bool {.inline.} =
|
2018-10-19 13:41:04 +00:00
|
|
|
for i in 0..18:
|
2018-10-02 14:46:39 +00:00
|
|
|
if computation.msg.codeAddress[i] != 0: return
|
2018-10-05 09:15:04 +00:00
|
|
|
|
2018-10-19 13:41:04 +00:00
|
|
|
let lb = computation.msg.codeAddress[19]
|
2019-11-11 04:21:16 +00:00
|
|
|
let maxPrecompileAddr = getMaxPrecompileAddr(fork)
|
2019-04-02 06:05:42 +00:00
|
|
|
if lb in PrecompileAddresses.low.byte .. maxPrecompileAddr.byte:
|
2018-10-02 14:46:39 +00:00
|
|
|
result = true
|
|
|
|
let precompile = PrecompileAddresses(lb)
|
Tracing: Remove some trace messages that occur a lot during sync
Disable some trace messages which appeared a lot in the output and probably
aren't so useful any more, when block processing is functioning well at high
speed.
Turning on the trace level globally is useful to get a feel for what's
happening, but only if each category is kept to a reasonable amount.
As well as overwhelming the output so that it's hard to see general activity,
some of these messages happen so much they severely slow down processing. Ones
called every time an EVM opcode uses some gas are particularly extreme.
These messages have all been chosen as things which are probably not useful any
more (the relevant functionality has been debugged and is tested plenty).
These have been commented out rather than removed. It may be that turning
trace topics on/off, or other selection, is a better longer term solution, but
that will require better command line options and good defaults for sure.
(I think higher levels `tracev` and `tracevv` levels (extra verbose) would be
more useful for this sort of deep tracing on request.)
For now, enabling `--log-level:TRACE` on the command line is quite useful as
long as we keep each category reasonable, and this patch tries to keep that
balance.
- Don't show "has transactions" on virtually every block imported.
- Don't show "Sender" and "txHash" lines on every transaction processed.
- Don't show "GAS CONSUMPTION" on every opcode executed", this is way too much.
- Don't show "GAS RETURNED" and "GAS REFUND" on each contract call.
- Don't show "op: Stop" on every Stop opcode, which means every transaction.
- Don't show "Insufficient funds" whenever a contract can't call another.
- Don't show "ECRecover", "SHA256 precompile", "RIPEMD160", "Identity"
or even "Call precompile" every time a precompile is called. These are
very well tested now.
- Don't show "executeOpcodes error" whenever a contract returns an error.
(This is changed to `trace` too, it's a normal event that is well tested.)
Signed-off-by: Jamie Lokier <jamie@shareable.org>
2021-07-22 13:35:41 +00:00
|
|
|
#trace "Call precompile", precompile = precompile, codeAddr = computation.msg.codeAddress
|
2019-03-11 11:50:13 +00:00
|
|
|
try:
|
|
|
|
case precompile
|
|
|
|
of paEcRecover: ecRecover(computation)
|
|
|
|
of paSha256: sha256(computation)
|
|
|
|
of paRipeMd160: ripeMd160(computation)
|
|
|
|
of paIdentity: identity(computation)
|
2020-11-24 09:19:02 +00:00
|
|
|
of paModExp: modExp(computation, fork)
|
2019-11-11 04:33:56 +00:00
|
|
|
of paEcAdd: bn256ecAdd(computation, fork)
|
|
|
|
of paEcMul: bn256ecMul(computation, fork)
|
|
|
|
of paPairing: bn256ecPairing(computation, fork)
|
2019-11-11 04:21:16 +00:00
|
|
|
of paBlake2bf: blake2bf(computation)
|
2021-05-16 12:44:24 +00:00
|
|
|
# EIP 2537: disabled
|
|
|
|
# reason: not included in berlin
|
|
|
|
# of paBlsG1Add: blsG1Add(computation)
|
|
|
|
# of paBlsG1Mul: blsG1Mul(computation)
|
|
|
|
# of paBlsG1MultiExp: blsG1MultiExp(computation)
|
|
|
|
# of paBlsG2Add: blsG2Add(computation)
|
|
|
|
# of paBlsG2Mul: blsG2Mul(computation)
|
|
|
|
# of paBlsG2MultiExp: blsG2MultiExp(computation)
|
|
|
|
# of paBlsPairing: blsPairing(computation)
|
|
|
|
# of paBlsMapG1: blsMapG1(computation)
|
|
|
|
# of paBlsMapG2: blsMapG2(computation)
|
2019-12-04 12:36:16 +00:00
|
|
|
except OutOfGas as e:
|
2019-04-24 05:56:10 +00:00
|
|
|
# cannot use setError here, cyclic dependency
|
2019-12-04 12:36:16 +00:00
|
|
|
computation.error = Error(info: e.msg, burnsGas: true)
|
|
|
|
except CatchableError as e:
|
2019-04-24 05:56:10 +00:00
|
|
|
if fork >= FKByzantium and precompile > paIdentity:
|
2019-12-04 12:36:16 +00:00
|
|
|
computation.error = Error(info: e.msg, burnsGas: true)
|
2019-04-24 05:56:10 +00:00
|
|
|
else:
|
|
|
|
# swallow any other precompiles errors
|
2019-12-04 12:36:16 +00:00
|
|
|
debug "execPrecompiles validation error", msg=e.msg
|