UNPKG

sevm

Version:

A Symbolic Ethereum Virtual Machine (EVM) bytecode decompiler & analyzer library & CLI

345 lines 9.96 kB
"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