ethereum.tangerine_whistle.vm.instructions.arithmetic

Ethereum Virtual Machine (EVM) Arithmetic Instructions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. contents:: Table of Contents :backlinks: none :local:

Introduction

Implementations of the EVM Arithmetic instructions.

add

Adds the top two elements of the stack together, and pushes the result back on the stack.

Parameters

evm : The current EVM frame.

def add(evm: Evm) -> None:
32
    """
33
    Adds the top two elements of the stack together, and pushes the result back
34
    on the stack.
35
36
    Parameters
37
    ----------
38
    evm :
39
        The current EVM frame.
40
41
    """
42
    # STACK
43
    x = pop(evm.stack)
44
    y = pop(evm.stack)
45
46
    # GAS
47
    charge_gas(evm, GAS_VERY_LOW)
48
49
    # OPERATION
50
    result = x.wrapping_add(y)
51
52
    push(evm.stack, result)
53
54
    # PROGRAM COUNTER
55
    evm.pc += Uint(1)

sub

Subtracts the top two elements of the stack, and pushes the result back on the stack.

Parameters

evm : The current EVM frame.

def sub(evm: Evm) -> None:
59
    """
60
    Subtracts the top two elements of the stack, and pushes the result back
61
    on the stack.
62
63
    Parameters
64
    ----------
65
    evm :
66
        The current EVM frame.
67
68
    """
69
    # STACK
70
    x = pop(evm.stack)
71
    y = pop(evm.stack)
72
73
    # GAS
74
    charge_gas(evm, GAS_VERY_LOW)
75
76
    # OPERATION
77
    result = x.wrapping_sub(y)
78
79
    push(evm.stack, result)
80
81
    # PROGRAM COUNTER
82
    evm.pc += Uint(1)

mul

Multiply the top two elements of the stack, and pushes the result back on the stack.

Parameters

evm : The current EVM frame.

def mul(evm: Evm) -> None:
86
    """
87
    Multiply the top two elements of the stack, and pushes the result back
88
    on the stack.
89
90
    Parameters
91
    ----------
92
    evm :
93
        The current EVM frame.
94
95
    """
96
    # STACK
97
    x = pop(evm.stack)
98
    y = pop(evm.stack)
99
100
    # GAS
101
    charge_gas(evm, GAS_LOW)
102
103
    # OPERATION
104
    result = x.wrapping_mul(y)
105
106
    push(evm.stack, result)
107
108
    # PROGRAM COUNTER
109
    evm.pc += Uint(1)

div

Integer division of the top two elements of the stack. Pushes the result back on the stack.

Parameters

evm : The current EVM frame.

def div(evm: Evm) -> None:
113
    """
114
    Integer division of the top two elements of the stack. Pushes the result
115
    back on the stack.
116
117
    Parameters
118
    ----------
119
    evm :
120
        The current EVM frame.
121
122
    """
123
    # STACK
124
    dividend = pop(evm.stack)
125
    divisor = pop(evm.stack)
126
127
    # GAS
128
    charge_gas(evm, GAS_LOW)
129
130
    # OPERATION
131
    if divisor == 0:
132
        quotient = U256(0)
133
    else:
134
        quotient = dividend // divisor
135
136
    push(evm.stack, quotient)
137
138
    # PROGRAM COUNTER
139
    evm.pc += Uint(1)

U255_CEIL_VALUE

142
U255_CEIL_VALUE = 2**255

sdiv

Signed integer division of the top two elements of the stack. Pushes the result back on the stack.

Parameters

evm : The current EVM frame.

def sdiv(evm: Evm) -> None:
146
    """
147
    Signed integer division of the top two elements of the stack. Pushes the
148
    result back on the stack.
149
150
    Parameters
151
    ----------
152
    evm :
153
        The current EVM frame.
154
155
    """
156
    # STACK
157
    dividend = pop(evm.stack).to_signed()
158
    divisor = pop(evm.stack).to_signed()
159
160
    # GAS
161
    charge_gas(evm, GAS_LOW)
162
163
    # OPERATION
164
    if divisor == 0:
165
        quotient = 0
166
    elif dividend == -U255_CEIL_VALUE and divisor == -1:
167
        quotient = -U255_CEIL_VALUE
168
    else:
169
        sign = get_sign(dividend * divisor)
170
        quotient = sign * (abs(dividend) // abs(divisor))
171
172
    push(evm.stack, U256.from_signed(quotient))
173
174
    # PROGRAM COUNTER
175
    evm.pc += Uint(1)

mod

Modulo remainder of the top two elements of the stack. Pushes the result back on the stack.

Parameters

evm : The current EVM frame.

def mod(evm: Evm) -> None:
179
    """
180
    Modulo remainder of the top two elements of the stack. Pushes the result
181
    back on the stack.
182
183
    Parameters
184
    ----------
185
    evm :
186
        The current EVM frame.
187
188
    """
189
    # STACK
190
    x = pop(evm.stack)
191
    y = pop(evm.stack)
192
193
    # GAS
194
    charge_gas(evm, GAS_LOW)
195
196
    # OPERATION
197
    if y == 0:
198
        remainder = U256(0)
199
    else:
200
        remainder = x % y
201
202
    push(evm.stack, remainder)
203
204
    # PROGRAM COUNTER
205
    evm.pc += Uint(1)

smod

Signed modulo remainder of the top two elements of the stack. Pushes the result back on the stack.

Parameters

evm : The current EVM frame.

def smod(evm: Evm) -> None:
209
    """
210
    Signed modulo remainder of the top two elements of the stack. Pushes the
211
    result back on the stack.
212
213
    Parameters
214
    ----------
215
    evm :
216
        The current EVM frame.
217
218
    """
219
    # STACK
220
    x = pop(evm.stack).to_signed()
221
    y = pop(evm.stack).to_signed()
222
223
    # GAS
224
    charge_gas(evm, GAS_LOW)
225
226
    # OPERATION
227
    if y == 0:
228
        remainder = 0
229
    else:
230
        remainder = get_sign(x) * (abs(x) % abs(y))
231
232
    push(evm.stack, U256.from_signed(remainder))
233
234
    # PROGRAM COUNTER
235
    evm.pc += Uint(1)

addmod

Modulo addition of the top 2 elements with the 3rd element. Pushes the result back on the stack.

Parameters

evm : The current EVM frame.

def addmod(evm: Evm) -> None:
239
    """
240
    Modulo addition of the top 2 elements with the 3rd element. Pushes the
241
    result back on the stack.
242
243
    Parameters
244
    ----------
245
    evm :
246
        The current EVM frame.
247
248
    """
249
    # STACK
250
    x = Uint(pop(evm.stack))
251
    y = Uint(pop(evm.stack))
252
    z = Uint(pop(evm.stack))
253
254
    # GAS
255
    charge_gas(evm, GAS_MID)
256
257
    # OPERATION
258
    if z == 0:
259
        result = U256(0)
260
    else:
261
        result = U256((x + y) % z)
262
263
    push(evm.stack, result)
264
265
    # PROGRAM COUNTER
266
    evm.pc += Uint(1)

mulmod

Modulo multiplication of the top 2 elements with the 3rd element. Pushes the result back on the stack.

Parameters

evm : The current EVM frame.

def mulmod(evm: Evm) -> None:
270
    """
271
    Modulo multiplication of the top 2 elements with the 3rd element. Pushes
272
    the result back on the stack.
273
274
    Parameters
275
    ----------
276
    evm :
277
        The current EVM frame.
278
279
    """
280
    # STACK
281
    x = Uint(pop(evm.stack))
282
    y = Uint(pop(evm.stack))
283
    z = Uint(pop(evm.stack))
284
285
    # GAS
286
    charge_gas(evm, GAS_MID)
287
288
    # OPERATION
289
    if z == 0:
290
        result = U256(0)
291
    else:
292
        result = U256((x * y) % z)
293
294
    push(evm.stack, result)
295
296
    # PROGRAM COUNTER
297
    evm.pc += Uint(1)

exp

Exponential operation of the top 2 elements. Pushes the result back on the stack.

Parameters

evm : The current EVM frame.

def exp(evm: Evm) -> None:
301
    """
302
    Exponential operation of the top 2 elements. Pushes the result back on
303
    the stack.
304
305
    Parameters
306
    ----------
307
    evm :
308
        The current EVM frame.
309
310
    """
311
    # STACK
312
    base = Uint(pop(evm.stack))
313
    exponent = Uint(pop(evm.stack))
314
315
    # GAS
316
    # This is equivalent to 1 + floor(log(y, 256)). But in python the log
317
    # function is inaccurate leading to wrong results.
318
    exponent_bits = exponent.bit_length()
319
    exponent_bytes = (exponent_bits + Uint(7)) // Uint(8)
320
    charge_gas(
321
        evm, GAS_EXPONENTIATION + GAS_EXPONENTIATION_PER_BYTE * exponent_bytes
322
    )
323
324
    # OPERATION
325
    result = U256(pow(base, exponent, Uint(U256.MAX_VALUE) + Uint(1)))
326
327
    push(evm.stack, result)
328
329
    # PROGRAM COUNTER
330
    evm.pc += Uint(1)

signextend

Sign extend operation. In other words, extend a signed number which fits in N bytes to 32 bytes.

Parameters

evm : The current EVM frame.

def signextend(evm: Evm) -> None:
334
    """
335
    Sign extend operation. In other words, extend a signed number which
336
    fits in N bytes to 32 bytes.
337
338
    Parameters
339
    ----------
340
    evm :
341
        The current EVM frame.
342
343
    """
344
    # STACK
345
    byte_num = pop(evm.stack)
346
    value = pop(evm.stack)
347
348
    # GAS
349
    charge_gas(evm, GAS_LOW)
350
351
    # OPERATION
352
    if byte_num > U256(31):
353
        # Can't extend any further
354
        result = value
355
    else:
356
        # U256(0).to_be_bytes() gives b'' instead b'\x00'.
357
        value_bytes = bytes(value.to_be_bytes32())
358
        # Now among the obtained value bytes, consider only
359
        # N `least significant bytes`, where N is `byte_num + 1`.
360
        value_bytes = value_bytes[31 - int(byte_num) :]
361
        sign_bit = value_bytes[0] >> 7
362
        if sign_bit == 0:
363
            result = U256.from_be_bytes(value_bytes)
364
        else:
365
            num_bytes_prepend = U256(32) - (byte_num + U256(1))
366
            result = U256.from_be_bytes(
367
                bytearray([0xFF] * num_bytes_prepend) + value_bytes
368
            )
369
370
    push(evm.stack, result)
371
372
    # PROGRAM COUNTER
373
    evm.pc += Uint(1)