UNPKG

@tokamak-zk-evm/synthesizer

Version:

Tokamak zk-EVM Synthesizer - Processes Ethereum transactions into wire maps for Tokamak zk-SNARK proof generation

213 lines 6.43 kB
import { convertToSigned } from '../utils/index.js'; /** * Utility class for handling Synthesizer arithmetic operations */ export class ArithmeticOperations { /** * Basic arithmetic operations */ static add(a, b) { return (a + b) & ArithmeticOperations.MAX_UINT256; } static mul(a, b) { return (a * b) & ArithmeticOperations.MAX_UINT256; } static sub(a, b) { return (a - b) & ArithmeticOperations.MAX_UINT256; } static div(a, b) { return b === 0n ? 0n : a / b; } static sdiv(a, b) { if (b === 0n) return 0n; const signedA = convertToSigned(a); const signedB = convertToSigned(b); const result = signedA / signedB; return result < 0n ? ArithmeticOperations.MAX_UINT256 + result + 1n : result; } /** * Modulo operations */ static mod(a, b) { return b === 0n ? 0n : a % b; } static smod(a, b) { if (b === 0n) return 0n; const signedA = convertToSigned(a); const signedB = convertToSigned(b); const result = signedA % signedB; return result < 0n ? ArithmeticOperations.MAX_UINT256 + result + 1n : result; } static addmod(a, b, N) { if (N === 0n) return 0n; return ((a % N) + (b % N)) % N; } static mulmod(a, b, N) { if (N === 0n) return 0n; return ((a % N) * (b % N)) % N; } /** * @deprecated * Exponentiation operation */ static exp(base, exponent) { if (exponent === 0n) return 1n; if (base === 0n) return 0n; let result = 1n; let currentBase = base; let currentExp = exponent; while (currentExp > 0n) { if (currentExp & 1n) { result = (result * currentBase) & ArithmeticOperations.MAX_UINT256; } currentBase = (currentBase * currentBase) & ArithmeticOperations.MAX_UINT256; currentExp >>= 1n; } return result; } /** * Comparison operations */ static lt(a, b) { return a < b ? 1n : 0n; } static gt(a, b) { return a > b ? 1n : 0n; } static slt(a, b) { return convertToSigned(a) < convertToSigned(b) ? 1n : 0n; } static sgt(a, b) { return convertToSigned(a) > convertToSigned(b) ? 1n : 0n; } static eq(a, b) { return a === b ? 1n : 0n; } static iszero(a) { return a === 0n ? 1n : 0n; } /** * Bit operations */ static and(a, b) { return a & b; } static or(a, b) { return a | b; } static xor(a, b) { return a ^ b; } static not(a) { return ~a & ArithmeticOperations.MAX_UINT256; } /** * Shift operations */ static shl(shift, value) { return shift >= 256n ? 0n : (value << shift) & ArithmeticOperations.MAX_UINT256; } static shr(shift, value) { return shift >= 256n ? 0n : value >> shift; } static sar(shift, value) { if (shift >= 256n) { return (value & (1n << 255n)) === 0n ? 0n : ArithmeticOperations.MAX_UINT256; } const isNegative = (value & (1n << 255n)) !== 0n; if (isNegative) { const mask = ArithmeticOperations.MAX_UINT256 << (256n - shift); // Apply the mask to the shifted value and ensure the result is within 256 bits return BigInt.asUintN(256, (value >> shift) | mask); } // For non-negative values, simply shift right return value >> shift; } /** * Byte operations */ static byte(index, value) { if (index >= 32n) return 0n; const shiftBits = (31n - index) * 8n; return (value >> shiftBits) & 0xffn; } /** * Sign extension */ static signextend(k, value) { if (k > 31n) return value; const bitPos = (k + 1n) * 8n - 1n; const signBit = (value >> bitPos) & 1n; if (signBit === 1n) { const mask = ((1n << (256n - bitPos)) - 1n) << bitPos; return value | mask; } else { const mask = (1n << (bitPos + 1n)) - 1n; return value & mask; } } /** * Decimal to Bit */ static decToBit(dec) { const binaryString = dec.toString(2); const paddedBinaryString = binaryString.padStart(256, '0'); const bits = Array.from(paddedBinaryString, (bit) => BigInt(bit)); return bits; } /** * Subroutine for EXP */ static subEXP(c, a, b) { if (!(b === 0n || b === 1n)) { throw new Error(`Synthesizer: ArithmeticOperations: subEXP: b is not binary`); } const aOut = (a * a) % ArithmeticOperations.N; const cOut = (c * (b * a + (1n - b))) % ArithmeticOperations.N; // <=> c * (b ? aOut : 1) return [cOut, aOut]; } } ArithmeticOperations.MAX_UINT256 = (1n << 256n) - 1n; ArithmeticOperations.SIGN_BIT = 1n << 255n; // N is 2^256, copied from opcodes/utils.ts. Used as modulo in EXP operations ArithmeticOperations.N = BigInt(115792089237316195423570985008687907853269984665640564039457584007913129639936); // Operator and function mapping export const OPERATION_MAPPING = { ADD: ArithmeticOperations.add, MUL: ArithmeticOperations.mul, SUB: ArithmeticOperations.sub, DIV: ArithmeticOperations.div, SDIV: ArithmeticOperations.sdiv, MOD: ArithmeticOperations.mod, SMOD: ArithmeticOperations.smod, ADDMOD: ArithmeticOperations.addmod, MULMOD: ArithmeticOperations.mulmod, EXP: ArithmeticOperations.exp, LT: ArithmeticOperations.lt, GT: ArithmeticOperations.gt, SLT: ArithmeticOperations.slt, SGT: ArithmeticOperations.sgt, EQ: ArithmeticOperations.eq, ISZERO: ArithmeticOperations.iszero, AND: ArithmeticOperations.and, OR: ArithmeticOperations.or, XOR: ArithmeticOperations.xor, NOT: ArithmeticOperations.not, SHL: ArithmeticOperations.shl, SHR: ArithmeticOperations.shr, SAR: ArithmeticOperations.sar, BYTE: ArithmeticOperations.byte, SIGNEXTEND: ArithmeticOperations.signextend, DecToBit: ArithmeticOperations.decToBit, SubEXP: ArithmeticOperations.subEXP, }; //# sourceMappingURL=arithmetic.js.map