sevm
Version:
A Symbolic Ethereum Virtual Machine (EVM) bytecode decompiler & analyzer library & CLI
345 lines • 9.96 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Sar = exports.Shr = exports.Shl = exports.Byte = exports.Not = exports.Xor = exports.Or = exports.And = exports.IsZero = exports.Eq = exports.Gt = exports.Lt = exports.Exp = exports.Mod = exports.Div = exports.Sub = exports.Mul = exports.Add = void 0;
const index_1 = require("./index");
class Bin extends index_1.Tag {
constructor(left, right) {
super(Math.max(left.depth, right.depth) + 1, left.count + right.count + 1);
this.left = left;
this.right = right;
}
}
/**
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_NOT
*
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Remainder
*
* > For `BigInt`s, there's no truncation.
* > Conceptually, understand positive `BigInt`s as having an infinite number of leading 0 bits,
* > and negative `BigInt`s having an infinite number of leading 1 bits.
*/
const mod256 = (n) => ((n % index_1.MOD_256) + index_1.MOD_256) % index_1.MOD_256;
/**
* Ensures the operation indicated by `fn` is not out of `BigInt`'s maximum size range.
*
* @param fn the operation to perform. Should be `exp` or `shl`.
* @returns the value computed by `fn` or `null` if `fn` throws `RangeError`.
*/
function withinMaxBigintRange(fn) {
try {
return fn();
}
catch {
// `RangeError: Maximum BigInt size exceeded`
return null;
}
}
class Add extends Bin {
constructor() {
super(...arguments);
this.tag = 'Add';
}
eval() {
const left = this.left.eval();
const right = this.right.eval();
return left.isVal() && right.isVal()
? new index_1.Val(mod256(left.val + right.val))
: left.isZero()
? right
: right.isZero()
? left
: new Add(left, right);
}
}
exports.Add = Add;
class Mul extends Bin {
constructor() {
super(...arguments);
this.tag = 'Mul';
}
eval() {
const lhs = this.left.eval();
const rhs = this.right.eval();
return lhs.isVal() && rhs.isVal()
? new index_1.Val(mod256(lhs.val * rhs.val))
: lhs.isZero() || rhs.isZero()
? new index_1.Val(0n)
: new Mul(lhs, rhs);
}
}
exports.Mul = Mul;
class Sub extends Bin {
constructor() {
super(...arguments);
this.tag = 'Sub';
}
eval() {
const left = this.left.eval();
const right = this.right.eval();
return left.isVal() && right.isVal()
? new index_1.Val(mod256(left.val - right.val))
: right.isZero()
? left
: new Sub(left, right);
}
}
exports.Sub = Sub;
class Div extends Bin {
constructor() {
super(...arguments);
this.tag = 'Div';
}
eval() {
const left = this.left.eval();
const right = this.right.eval();
return left.isVal() && right.isVal()
? right.val === 0n
? new Div(left, right)
: new index_1.Val(left.val / right.val)
: right.isVal() && right.val === 1n
? left
: new Div(left, right);
}
}
exports.Div = Div;
class Mod extends Bin {
constructor() {
super(...arguments);
this.tag = 'Mod';
}
eval() {
const lhs = this.left.eval();
const rhs = this.right.eval();
return lhs.isVal() && rhs.isVal() && rhs.val !== 0n
? new index_1.Val(lhs.val % rhs.val)
: new Mod(lhs, rhs);
}
}
exports.Mod = Mod;
/**
* Represents the Exponential operation. https://www.evm.codes/#0a
*
* `eval` definition
*
* ```txt
* µ'_s[0] ≡ µ_s[0] ^ µ_s[1]
* ```
*/
class Exp extends Bin {
constructor() {
super(...arguments);
this.tag = 'Exp';
}
eval() {
const left = this.left.eval();
const right = this.right.eval();
if (left.isVal() && right.isVal() && right.val >= 0) {
const value = withinMaxBigintRange(() => left.val ** right.val);
if (value !== null) {
return new index_1.Val(mod256(value));
}
}
return new Exp(left, right);
}
}
exports.Exp = Exp;
class Cmp extends index_1.Tag {
constructor(left, right, equal = false) {
super(Math.max(left.depth, right.depth) + 1, left.count + right.count + 1);
this.left = left;
this.right = right;
this.equal = equal;
}
}
class Unary extends index_1.Tag {
constructor(value) {
super(value.depth + 1, value.count + 1);
this.value = value;
}
}
class Shift extends index_1.Tag {
constructor(value, shift) {
super(Math.max(value.depth, shift.depth) + 1, value.count + shift.count + 1);
this.value = value;
this.shift = shift;
}
}
class Lt extends Cmp {
constructor() {
super(...arguments);
this.tag = 'Lt';
}
eval() {
const lhs = this.left.eval();
const rhs = this.right.eval();
return lhs.isVal() && rhs.isVal() ? new index_1.Val(lhs.val < rhs.val ? 1n : 0n) : new Lt(lhs, rhs);
}
}
exports.Lt = Lt;
class Gt extends Cmp {
constructor() {
super(...arguments);
this.tag = 'Gt';
}
eval() {
const lhs = this.left.eval();
const rhs = this.right.eval();
return lhs.isVal() && rhs.isVal() ? new index_1.Val(lhs.val > rhs.val ? 1n : 0n) : new Gt(lhs, rhs);
}
}
exports.Gt = Gt;
class Eq extends Bin {
constructor() {
super(...arguments);
this.tag = 'Eq';
}
eval() {
return new Eq(this.left.eval(), this.right.eval());
}
}
exports.Eq = Eq;
class IsZero extends index_1.Tag {
constructor(value) {
super(value.depth + 1, value.count + 1);
this.value = value;
this.tag = 'IsZero';
}
eval() {
const val = this.value.eval();
return val.isVal()
? val.val === 0n
? new index_1.Val(1n)
: new index_1.Val(0n)
: val.tag === 'Lt'
? new Gt(val.left, val.right, !val.equal)
: val.tag === 'Gt'
? new Lt(val.left, val.right, !val.equal)
: val.tag === 'IsZero'
? val.value
: new IsZero(val);
}
}
exports.IsZero = IsZero;
class And extends Bin {
constructor() {
super(...arguments);
this.tag = 'And';
}
eval() {
const lhs = this.left.eval();
const rhs = this.right.eval();
return lhs.isVal() && rhs.isVal()
? new index_1.Val(lhs.val & rhs.val)
: lhs.isVal() && /^[f]+$/.test(lhs.val.toString(16))
? rhs
: rhs.isVal() && /^[f]+$/.test(rhs.val.toString(16))
? lhs
: lhs.isVal() && rhs.tag === 'And' && rhs.left.isVal() && lhs.val === rhs.left.val
? rhs.right
: new And(lhs, rhs);
}
}
exports.And = And;
class Or extends Bin {
constructor() {
super(...arguments);
this.tag = 'Or';
}
eval() {
const lhs = this.left.eval();
const rhs = this.right.eval();
return lhs.isVal() && rhs.isVal() ? new index_1.Val(lhs.val | rhs.val) : new Or(lhs, rhs);
}
}
exports.Or = Or;
class Xor extends Bin {
constructor() {
super(...arguments);
this.tag = 'Xor';
}
eval() {
const lhs = this.left.eval();
const rhs = this.right.eval();
return lhs.isVal() && rhs.isVal() ? new index_1.Val(lhs.val ^ rhs.val) : new Xor(lhs, rhs);
}
}
exports.Xor = Xor;
class Not extends Unary {
constructor() {
super(...arguments);
this.tag = 'Not';
}
eval() {
const val = this.value.eval();
return val.isVal() ? new index_1.Val(mod256(~val.val)) : new Not(val);
}
}
exports.Not = Not;
class Byte extends index_1.Tag {
constructor(pos, data) {
super(Math.max(pos.depth, data.depth) + 1, pos.count + data.count + 1);
this.pos = pos;
this.data = data;
this.tag = 'Byte';
}
eval() {
const pos = this.pos.eval();
const data = this.data.eval();
return data.isVal() && pos.isVal()
? new index_1.Val((data.val >> pos.val) & 1n)
: new Byte(pos, data);
}
}
exports.Byte = Byte;
/**
* Represents the Left shift operation. https://www.evm.codes/#1b
*
* `eval` definition
*
* ```txt
* µ'_s[0] ≡ (µ_s[1] × 2^µ_s[0]) mod 2^256
* ```
*/
class Shl extends Shift {
constructor() {
super(...arguments);
this.tag = 'Shl';
}
eval() {
const val = this.value.eval();
const shift = this.shift.eval();
if (val.isVal() && shift.isVal()) {
const value = withinMaxBigintRange(() => val.val << shift.val);
if (value !== null) {
return new index_1.Val(mod256(value));
}
}
return new Shl(val, shift);
}
}
exports.Shl = Shl;
class Shr extends Shift {
constructor() {
super(...arguments);
this.tag = 'Shr';
}
eval() {
const val = this.value.eval();
const shift = this.shift.eval();
return val.isVal() && shift.isVal() ? new index_1.Val(val.val >> shift.val) : new Shr(val, shift);
}
}
exports.Shr = Shr;
class Sar extends Shift {
constructor() {
super(...arguments);
this.tag = 'Sar';
}
eval() {
const val = this.value.eval();
const shift = this.shift.eval();
return val.isVal() && shift.isVal() ? new index_1.Val(val.val >> shift.val) : new Sar(val, shift);
}
}
exports.Sar = Sar;
//# sourceMappingURL=alu.js.map