Skip to content

Instantly share code, notes, and snippets.

@holgerd77
Created September 20, 2024 08:27
Show Gist options
  • Save holgerd77/2c032488196b4afee5d976dc85ee70eb to your computer and use it in GitHub Desktop.
Save holgerd77/2c032488196b4afee5d976dc85ee70eb to your computer and use it in GitHub Desktop.
Unminifed JS bundle of the EthereumJS EVM with all dependencies
const FORMAT = 239;
const MAGIC = 0;
const VERSION = 1;
const MAX_HEADER_SIZE = 49152;
const KIND_TYPE = 1;
const KIND_CODE = 2;
const KIND_CONTAINER = 3;
const KIND_DATA = 4;
const TERMINATOR = 0;
const TYPE_MIN = 4;
const TYPE_MAX = 4096;
const TYPE_DIVISOR = 4;
const CODE_MIN = 1;
const CODE_SIZE_MIN = 1;
const CONTAINER_MIN = 1;
const CONTAINER_MAX = 256;
const CONTAINER_SIZE_MIN = 1;
const INPUTS_MAX = 127;
const OUTPUTS_MAX = 128;
const MAX_STACK_HEIGHT = 1023;
var EOFError = /* @__PURE__ */ ((EOFError2) => {
EOFError2["OutOfBounds"] = "Trying to read out of bounds";
EOFError2["VerifyUint"] = "Uint does not match expected value ";
EOFError2["VerifyBytes"] = "Bytes do not match expected value";
EOFError2["FORMAT"] = "err: invalid format";
EOFError2["MAGIC"] = "err: invalid magic";
EOFError2["VERSION"] = `err: invalid eof version`;
EOFError2["KIND_TYPE"] = `err: expected kind types`;
EOFError2["KIND_CODE"] = `err: expected kind code`;
EOFError2["KIND_DATA"] = `err: expected kind data`;
EOFError2["TERMINATOR"] = `err: expected terminator`;
EOFError2["TypeSize"] = `missing type size`;
EOFError2["InvalidTypeSize"] = `err: type section size invalid`;
EOFError2["CodeSize"] = `missing code size`;
EOFError2["CodeSectionSize"] = `code section should be at least one byte`;
EOFError2["InvalidCodeSize"] = `code size does not match type size`;
EOFError2["DataSize"] = `missing data size`;
EOFError2["ContainerSize"] = "missing container size";
EOFError2["ContainerSectionSize"] = "container section should at least contain one section and at most 255 sections";
EOFError2["TypeSections"] = `err: mismatch of code sections count and type signatures`;
EOFError2["Inputs"] = "expected inputs";
EOFError2["Outputs"] = "expected outputs";
EOFError2["MaxInputs"] = "inputs exceeds 127, the maximum, got: ";
EOFError2["MaxOutputs"] = "outputs exceeds 127, the maximum, got: ";
EOFError2["Code0Inputs"] = "first code section should have 0 inputs";
EOFError2["Code0Outputs"] = "first code section should have 0x80 (terminating section) outputs";
EOFError2["MaxStackHeight"] = `expected maxStackHeight`;
EOFError2["MaxStackHeightLimit"] = `stack height limit of 1024 exceeded: `;
EOFError2["MinCodeSections"] = `should have at least 1 code section`;
EOFError2["MaxCodeSections"] = `can have at most 1024 code sections`;
EOFError2["CodeSection"] = `expected a code section`;
EOFError2["DataSection"] = `Expected data section`;
EOFError2["ContainerSection"] = "expected a container section";
EOFError2["ContainerSectionMin"] = "container section should be at least 1 byte";
EOFError2["InvalidEOFCreateTarget"] = "EOFCREATE targets an undefined container";
EOFError2["InvalidRETURNContractTarget"] = "RETURNCONTRACT targets an undefined container";
EOFError2["ContainerDoubleType"] = "Container is targeted by both EOFCREATE and RETURNCONTRACT";
EOFError2["UnreachableContainerSections"] = "Unreachable containers (by both EOFCREATE and RETURNCONTRACT)";
EOFError2["ContainerTypeError"] = "Container contains opcodes which this mode (deployment mode / init code / runtime mode) cannot have";
EOFError2["DanglingBytes"] = "got dangling bytes in body";
EOFError2["InvalidOpcode"] = "invalid opcode";
EOFError2["InvalidTerminator"] = "invalid terminating opcode";
EOFError2["OpcodeIntermediatesOOB"] = "invalid opcode: intermediates out-of-bounds";
EOFError2["InvalidRJUMP"] = "invalid rjump* target";
EOFError2["InvalidCallTarget"] = "invalid callf/jumpf target";
EOFError2["InvalidCALLFReturning"] = "invalid callf: calls to non-returning function";
EOFError2["InvalidStackHeight"] = "invalid stack height";
EOFError2["InvalidJUMPF"] = "invalid jumpf target (output count)";
EOFError2["InvalidReturningSection"] = "invalid returning code section: section is not returning";
EOFError2["RJUMPVTableSize0"] = "invalid RJUMPV: table size 0";
EOFError2["UnreachableCodeSections"] = "unreachable code sections";
EOFError2["UnreachableCode"] = "unreachable code (by forward jumps)";
EOFError2["DataLoadNOutOfBounds"] = "DATALOADN reading out of bounds";
EOFError2["MaxStackHeightViolation"] = "Max stack height does not match the reported max stack height";
EOFError2["StackUnderflow"] = "Stack underflow";
EOFError2["StackOverflow"] = "Stack overflow";
EOFError2["UnstableStack"] = "Unstable stack (can reach stack under/overflow by jumps)";
EOFError2["RetfNoReturn"] = "Trying to return to undefined function";
EOFError2["ReturnStackOverflow"] = "Return stack overflow";
EOFError2["InvalidExtcallTarget"] = "invalid extcall target: address > 20 bytes";
EOFError2["InvalidReturnContractDataSize"] = "invalid RETURNCONTRACT: data size lower than expected";
EOFError2["InvalidEofFormat"] = "invalid EOF format";
return EOFError2;
})(EOFError || {});
function validationError(type, ...args) {
switch (type) {
case "Trying to read out of bounds": {
const pos = args[0];
if (pos === 0 || pos === 2 || pos === 3 || pos === 6) {
throw new Error(args[1]);
}
throw new Error(`Trying to read out of bounds `);
}
case "Bytes do not match expected value": {
const pos = args[0];
if (pos === 0 || pos === 2 || pos === 3 || pos === 6) {
throw new Error(args[1]);
}
throw new Error(`Bytes do not match expected value at pos: ${args[0]}: ${args[1]}`);
}
case "Uint does not match expected value ": {
const pos = args[0];
if (pos === 0 || pos === 2 || pos === 3 || pos === 6 || pos === 18) {
throw new Error(args[1]);
}
throw new Error(`Uint does not match expected value at pos: ${args[0]}: ${args[1]}`);
}
case "missing type size": {
throw new Error("missing type size" + args[0]);
}
case "err: mismatch of code sections count and type signatures": {
throw new Error(`${"err: mismatch of code sections count and type signatures"} (types ${args[0]} code ${args[1]})`);
}
case "err: type section size invalid": {
throw new Error(
"err: type section size invalid"
/* InvalidTypeSize */
);
}
case "code size does not match type size": {
throw new Error("code size does not match type size" + args[0]);
}
case "expected inputs": {
throw new Error(`${"expected inputs"} - typeSection ${args[0]}`);
}
case "expected outputs": {
throw new Error(`${"expected outputs"} - typeSection ${args[0]}`);
}
case "first code section should have 0 inputs": {
throw new Error(`first code section should have 0 inputs`);
}
case "first code section should have 0x80 (terminating section) outputs": {
throw new Error(`first code section should have 0 outputs`);
}
case "inputs exceeds 127, the maximum, got: ": {
throw new Error(`inputs exceeds 127, the maximum, got: ${args[1]} - code section ${args[0]}`);
}
case "outputs exceeds 127, the maximum, got: ": {
throw new Error(`outputs exceeds 127, the maximum, got: ${args[1]} - code section ${args[0]}`);
}
case "expected a code section": {
throw new Error(`expected code: codeSection ${args[0]}: `);
}
case "Expected data section": {
throw new Error(
"Expected data section"
/* DataSection */
);
}
case "expected maxStackHeight": {
throw new Error(`${"expected maxStackHeight"} - typeSection ${args[0]}: `);
}
case "stack height limit of 1024 exceeded: ": {
throw new Error(`${"stack height limit of 1024 exceeded: "}, got: ${args[1]} - typeSection ${args[0]}`);
}
case "got dangling bytes in body": {
throw new Error(
"got dangling bytes in body"
/* DanglingBytes */
);
}
default: {
throw new Error(type);
}
}
}
const stackDelta = {
0: { inputs: 0, outputs: 0, name: "STOP", intermediates: 0, terminating: true },
1: { inputs: 2, outputs: 1, name: "ADD", intermediates: 0 },
2: { inputs: 2, outputs: 1, name: "MUL", intermediates: 0 },
3: { inputs: 2, outputs: 1, name: "SUB", intermediates: 0 },
4: { inputs: 2, outputs: 1, name: "DIV", intermediates: 0 },
5: { inputs: 2, outputs: 1, name: "SDIV", intermediates: 0 },
6: { inputs: 2, outputs: 1, name: "MOD", intermediates: 0 },
7: { inputs: 2, outputs: 1, name: "SMOD", intermediates: 0 },
8: { inputs: 3, outputs: 1, name: "ADDMOD", intermediates: 0 },
9: { inputs: 3, outputs: 1, name: "MULMOD", intermediates: 0 },
10: { inputs: 2, outputs: 1, name: "EXP", intermediates: 0 },
11: { inputs: 2, outputs: 1, name: "SIGNEXTEND", intermediates: 0 },
16: { inputs: 2, outputs: 1, name: "LT", intermediates: 0 },
17: { inputs: 2, outputs: 1, name: "GT", intermediates: 0 },
18: { inputs: 2, outputs: 1, name: "SLT", intermediates: 0 },
19: { inputs: 2, outputs: 1, name: "SGT", intermediates: 0 },
20: { inputs: 2, outputs: 1, name: "EQ", intermediates: 0 },
21: { inputs: 1, outputs: 1, name: "ISZERO", intermediates: 0 },
22: { inputs: 2, outputs: 1, name: "AND", intermediates: 0 },
23: { inputs: 2, outputs: 1, name: "OR", intermediates: 0 },
24: { inputs: 2, outputs: 1, name: "XOR", intermediates: 0 },
25: { inputs: 1, outputs: 1, name: "NOT", intermediates: 0 },
26: { inputs: 2, outputs: 1, name: "BYTE", intermediates: 0 },
27: { inputs: 2, outputs: 1, name: "SHL", intermediates: 0 },
28: { inputs: 2, outputs: 1, name: "SHR", intermediates: 0 },
29: { inputs: 2, outputs: 1, name: "SAR", intermediates: 0 },
32: { inputs: 2, outputs: 1, name: "SHA3", intermediates: 0 },
48: { inputs: 0, outputs: 1, name: "ADDRESS", intermediates: 0 },
49: { inputs: 1, outputs: 1, name: "BALANCE", intermediates: 0 },
50: { inputs: 0, outputs: 1, name: "ORIGIN", intermediates: 0 },
51: { inputs: 0, outputs: 1, name: "CALLER", intermediates: 0 },
52: { inputs: 0, outputs: 1, name: "CALLVALUE", intermediates: 0 },
53: { inputs: 1, outputs: 1, name: "CALLDATALOAD", intermediates: 0 },
54: { inputs: 0, outputs: 1, name: "CALLDATASIZE", intermediates: 0 },
55: { inputs: 3, outputs: 0, name: "CALLDATACOPY", intermediates: 0 },
58: { inputs: 0, outputs: 1, name: "GASPRICE", intermediates: 0 },
61: { inputs: 0, outputs: 1, name: "RETURNDATASIZE", intermediates: 0 },
62: { inputs: 3, outputs: 0, name: "RETURNDATACOPY", intermediates: 0 },
64: { inputs: 1, outputs: 1, name: "BLOCKHASH", intermediates: 0 },
65: { inputs: 0, outputs: 1, name: "COINBASE", intermediates: 0 },
66: { inputs: 0, outputs: 1, name: "TIMESTAMP", intermediates: 0 },
67: { inputs: 0, outputs: 1, name: "NUMBER", intermediates: 0 },
68: { inputs: 0, outputs: 1, name: "PREVRANDAO", intermediates: 0 },
69: { inputs: 0, outputs: 1, name: "GASLIMIT", intermediates: 0 },
70: { inputs: 0, outputs: 1, name: "CHAINID", intermediates: 0 },
71: { inputs: 0, outputs: 1, name: "SELFBALANCE", intermediates: 0 },
72: { inputs: 0, outputs: 1, name: "BASEFEE", intermediates: 0 },
73: { inputs: 1, outputs: 1, name: "BLOBAHASH", intermediates: 0 },
74: { inputs: 0, outputs: 1, name: "BLOBBASEFEE", intermediates: 0 },
80: { inputs: 1, outputs: 0, name: "POP", intermediates: 0 },
81: { inputs: 1, outputs: 1, name: "MLOAD", intermediates: 0 },
82: { inputs: 2, outputs: 0, name: "MSTORE", intermediates: 0 },
83: { inputs: 2, outputs: 0, name: "MSTORE8", intermediates: 0 },
84: { inputs: 1, outputs: 1, name: "SLOAD", intermediates: 0 },
85: { inputs: 2, outputs: 0, name: "SSTORE", intermediates: 0 },
89: { inputs: 0, outputs: 1, name: "MSIZE", intermediates: 0 },
91: { inputs: 0, outputs: 0, name: "NOOP", intermediates: 0 },
92: { inputs: 1, outputs: 1, name: "TLOAD", intermediates: 0 },
93: { inputs: 2, outputs: 0, name: "TSTORE", intermediates: 0 },
94: { inputs: 3, outputs: 0, name: "MCOPY", intermediates: 0 },
95: { inputs: 0, outputs: 1, name: "PUSH0", intermediates: 0 },
96: { inputs: 0, outputs: 1, name: "PUSH1", intermediates: 1 },
97: { inputs: 0, outputs: 1, name: "PUSH2", intermediates: 2 },
98: { inputs: 0, outputs: 1, name: "PUSH3", intermediates: 3 },
99: { inputs: 0, outputs: 1, name: "PUSH4", intermediates: 4 },
100: { inputs: 0, outputs: 1, name: "PUSH5", intermediates: 5 },
101: { inputs: 0, outputs: 1, name: "PUSH6", intermediates: 6 },
102: { inputs: 0, outputs: 1, name: "PUSH7", intermediates: 7 },
103: { inputs: 0, outputs: 1, name: "PUSH8", intermediates: 8 },
104: { inputs: 0, outputs: 1, name: "PUSH9", intermediates: 9 },
105: { inputs: 0, outputs: 1, name: "PUSH10", intermediates: 10 },
106: { inputs: 0, outputs: 1, name: "PUSH11", intermediates: 11 },
107: { inputs: 0, outputs: 1, name: "PUSH12", intermediates: 12 },
108: { inputs: 0, outputs: 1, name: "PUSH13", intermediates: 13 },
109: { inputs: 0, outputs: 1, name: "PUSH14", intermediates: 14 },
110: { inputs: 0, outputs: 1, name: "PUSH15", intermediates: 15 },
111: { inputs: 0, outputs: 1, name: "PUSH16", intermediates: 16 },
112: { inputs: 0, outputs: 1, name: "PUSH17", intermediates: 17 },
113: { inputs: 0, outputs: 1, name: "PUSH18", intermediates: 18 },
114: { inputs: 0, outputs: 1, name: "PUSH19", intermediates: 19 },
115: { inputs: 0, outputs: 1, name: "PUSH20", intermediates: 20 },
116: { inputs: 0, outputs: 1, name: "PUSH21", intermediates: 21 },
117: { inputs: 0, outputs: 1, name: "PUSH22", intermediates: 22 },
118: { inputs: 0, outputs: 1, name: "PUSH23", intermediates: 23 },
119: { inputs: 0, outputs: 1, name: "PUSH24", intermediates: 24 },
120: { inputs: 0, outputs: 1, name: "PUSH25", intermediates: 25 },
121: { inputs: 0, outputs: 1, name: "PUSH26", intermediates: 26 },
122: { inputs: 0, outputs: 1, name: "PUSH27", intermediates: 27 },
123: { inputs: 0, outputs: 1, name: "PUSH28", intermediates: 28 },
124: { inputs: 0, outputs: 1, name: "PUSH29", intermediates: 29 },
125: { inputs: 0, outputs: 1, name: "PUSH30", intermediates: 30 },
126: { inputs: 0, outputs: 1, name: "PUSH31", intermediates: 31 },
127: { inputs: 0, outputs: 1, name: "PUSH32", intermediates: 32 },
128: { inputs: 1, outputs: 2, name: "DUP1", intermediates: 0 },
129: { inputs: 2, outputs: 3, name: "DUP2", intermediates: 0 },
130: { inputs: 3, outputs: 4, name: "DUP3", intermediates: 0 },
131: { inputs: 4, outputs: 5, name: "DUP4", intermediates: 0 },
132: { inputs: 5, outputs: 6, name: "DUP5", intermediates: 0 },
133: { inputs: 6, outputs: 7, name: "DUP6", intermediates: 0 },
134: { inputs: 7, outputs: 8, name: "DUP7", intermediates: 0 },
135: { inputs: 8, outputs: 9, name: "DUP8", intermediates: 0 },
136: { inputs: 9, outputs: 10, name: "DUP9", intermediates: 0 },
137: { inputs: 10, outputs: 11, name: "DUP10", intermediates: 0 },
138: { inputs: 11, outputs: 12, name: "DUP11", intermediates: 0 },
139: { inputs: 12, outputs: 13, name: "DUP12", intermediates: 0 },
140: { inputs: 13, outputs: 14, name: "DUP13", intermediates: 0 },
141: { inputs: 14, outputs: 15, name: "DUP14", intermediates: 0 },
142: { inputs: 15, outputs: 16, name: "DUP15", intermediates: 0 },
143: { inputs: 16, outputs: 17, name: "DUP16", intermediates: 0 },
144: { inputs: 2, outputs: 2, name: "SWAP1", intermediates: 0 },
145: { inputs: 3, outputs: 3, name: "SWAP2", intermediates: 0 },
146: { inputs: 4, outputs: 4, name: "SWAP3", intermediates: 0 },
147: { inputs: 5, outputs: 5, name: "SWAP4", intermediates: 0 },
148: { inputs: 6, outputs: 6, name: "SWAP5", intermediates: 0 },
149: { inputs: 7, outputs: 7, name: "SWAP6", intermediates: 0 },
150: { inputs: 8, outputs: 8, name: "SWAP7", intermediates: 0 },
151: { inputs: 9, outputs: 9, name: "SWAP8", intermediates: 0 },
152: { inputs: 10, outputs: 10, name: "SWAP9", intermediates: 0 },
153: { inputs: 11, outputs: 11, name: "SWAP10", intermediates: 0 },
154: { inputs: 12, outputs: 12, name: "SWAP11", intermediates: 0 },
155: { inputs: 13, outputs: 13, name: "SWAP12", intermediates: 0 },
156: { inputs: 14, outputs: 14, name: "SWAP13", intermediates: 0 },
157: { inputs: 15, outputs: 15, name: "SWAP14", intermediates: 0 },
158: { inputs: 16, outputs: 16, name: "SWAP15", intermediates: 0 },
159: { inputs: 17, outputs: 17, name: "SWAP16", intermediates: 0 },
160: { inputs: 2, outputs: 0, name: "LOG0", intermediates: 0 },
161: { inputs: 3, outputs: 0, name: "LOG1", intermediates: 0 },
162: { inputs: 4, outputs: 0, name: "LOG2", intermediates: 0 },
163: { inputs: 5, outputs: 0, name: "LOG3", intermediates: 0 },
164: { inputs: 6, outputs: 0, name: "LOG4", intermediates: 0 },
208: { inputs: 1, outputs: 1, name: "DATALOAD", intermediates: 0 },
209: { inputs: 0, outputs: 1, name: "DATALOADN", intermediates: 2 },
210: { inputs: 0, outputs: 1, name: "DATASIZE", intermediates: 0 },
211: { inputs: 3, outputs: 0, name: "DATACOPY", intermediates: 0 },
224: { inputs: 0, outputs: 0, name: "RJUMP", intermediates: 2 },
225: { inputs: 1, outputs: 0, name: "RJUMPI", intermediates: 2 },
// NOTE: for RJUMPV the intermediate byte is set to 0, this has to do with the validation algorithm specifics
// This has to do with the dynamic intermediate size of RJUMPV, which depends upon the table size byte right after RJUMPV
226: { inputs: 1, outputs: 0, name: "RJUMPV", intermediates: 0 },
// CALLF special case for stack validation algorithm: the inputs and outputs MUST stay 0
// (this is currently the case also in EVM)
227: { inputs: 0, outputs: 0, name: "CALLF", intermediates: 2 },
228: { inputs: 0, outputs: 0, name: "RETF", intermediates: 0, terminating: true },
229: { inputs: 0, outputs: 0, name: "JUMPF", intermediates: 2, terminating: true },
230: { inputs: 0, outputs: 1, name: "DUPN", intermediates: 1 },
231: { inputs: 0, outputs: 0, name: "SWAPN", intermediates: 1 },
232: { inputs: 0, outputs: 0, name: "EXCHANGE", intermediates: 1 },
236: { inputs: 4, outputs: 1, name: "EOFCREATE", intermediates: 1 },
238: { inputs: 2, outputs: 0, name: "RETURNCONTRACT", intermediates: 1, terminating: true },
243: { inputs: 2, outputs: 0, name: "RETURN", intermediates: 0, terminating: true },
247: { inputs: 1, outputs: 1, name: "RETURNDATALOAD", intermediates: 0 },
248: { inputs: 4, outputs: 1, name: "EXTCALL", intermediates: 0 },
249: { inputs: 3, outputs: 1, name: "EXTDELEGATECALL", intermediates: 0 },
251: { inputs: 3, outputs: 1, name: "EXTSTATICCALL", intermediates: 0 },
253: { inputs: 2, outputs: 0, name: "REVERT", intermediates: 0, terminating: true },
254: { inputs: 0, outputs: 0, name: "INVALID", intermediates: 0, terminating: true }
};
var ContainerSectionType = /* @__PURE__ */ ((ContainerSectionType2) => {
ContainerSectionType2[ContainerSectionType2["InitCode"] = 0] = "InitCode";
ContainerSectionType2[ContainerSectionType2["DeploymentCode"] = 1] = "DeploymentCode";
ContainerSectionType2[ContainerSectionType2["RuntimeCode"] = 2] = "RuntimeCode";
return ContainerSectionType2;
})(ContainerSectionType || {});
function verifyCode(container, evm, mode = 2) {
return validateOpcodes(container, evm, mode);
}
function readInt16(code, start) {
return new DataView(code.buffer).getInt16(start);
}
function readUint16(code, start) {
return new DataView(code.buffer).getUint16(start);
}
function validateOpcodes(container, evm, mode = 2) {
const intermediateBytes = /* @__PURE__ */ new Set();
const jumpLocations = /* @__PURE__ */ new Set();
const containerTypeMap = /* @__PURE__ */ new Map();
function addJump(location) {
if (intermediateBytes.has(location)) {
validationError(EOFError.InvalidRJUMP);
}
jumpLocations.add(location);
}
function addIntermediate(location) {
if (jumpLocations.has(location)) {
validationError(EOFError.InvalidRJUMP);
}
intermediateBytes.add(location);
}
const opcodes2 = evm.getActiveOpcodes();
const opcodeNumbers = /* @__PURE__ */ new Set();
for (const [key] of opcodes2) {
opcodeNumbers.add(key);
}
opcodeNumbers.add(254);
opcodeNumbers.delete(56);
opcodeNumbers.delete(57);
opcodeNumbers.delete(90);
opcodeNumbers.delete(59);
opcodeNumbers.delete(60);
opcodeNumbers.delete(63);
opcodeNumbers.delete(242);
opcodeNumbers.delete(255);
opcodeNumbers.delete(86);
opcodeNumbers.delete(87);
opcodeNumbers.delete(88);
opcodeNumbers.delete(240);
opcodeNumbers.delete(245);
const terminatingOpcodes = /* @__PURE__ */ new Set();
terminatingOpcodes.add(0);
terminatingOpcodes.add(243);
terminatingOpcodes.add(253);
terminatingOpcodes.add(254);
terminatingOpcodes.add(238);
terminatingOpcodes.add(228);
terminatingOpcodes.add(229);
terminatingOpcodes.add(224);
for (const opcode of terminatingOpcodes) {
if (!opcodeNumbers.has(opcode)) {
terminatingOpcodes.delete(opcode);
}
}
const validJumps = /* @__PURE__ */ new Set();
const reachableSections = {};
let codeSection = -1;
for (const code of container.body.codeSections) {
codeSection++;
reachableSections[codeSection] = /* @__PURE__ */ new Set();
const returningFunction = container.body.typeSections[codeSection].outputs === 128;
const reachableOpcodes = /* @__PURE__ */ new Set();
reachableOpcodes.add(0);
let ptr = 0;
let lastOpcode = 0;
const inputs = container.body.typeSections[codeSection].inputs;
let maxStackHeight = inputs;
const stackHeightMin = [inputs];
const stackHeightMax = [inputs];
while (ptr < code.length) {
const successorSet = /* @__PURE__ */ new Set();
if (!reachableOpcodes.has(ptr)) {
validationError(EOFError.UnreachableCode);
}
if (stackHeightMin[ptr] === void 0 || stackHeightMax[ptr] === void 0) {
validationError(EOFError.UnreachableCode);
}
validJumps.add(ptr);
const opcode = code[ptr];
const minStackCurrent = stackHeightMin[ptr];
const maxStackCurrent = stackHeightMax[ptr];
const opcodeInputs = stackDelta[opcode].inputs;
const opcodeOutputs = stackDelta[opcode].outputs;
if (minStackCurrent - opcodeInputs < 0) {
validationError(EOFError.StackUnderflow);
}
const delta = opcodeOutputs - opcodeInputs;
let minStackNext = minStackCurrent + delta;
let maxStackNext = maxStackCurrent + delta;
if (maxStackNext > 1023) {
validationError(EOFError.StackOverflow);
}
if (returningFunction && opcode === 228) {
validationError(EOFError.InvalidReturningSection);
}
lastOpcode = opcode;
if (!opcodeNumbers.has(opcode)) {
validationError(EOFError.InvalidOpcode);
}
if (opcode === 224 || opcode === 225) {
const target = readInt16(code, ptr + 1) + ptr + 3;
if (target < 0 || target >= code.length) {
validationError(EOFError.InvalidRJUMP);
}
successorSet.add(target);
addJump(target);
reachableOpcodes.add(target);
if (opcode === 224) {
if (!reachableOpcodes.has(ptr + 3) && ptr + 3 < code.length) {
validationError(EOFError.UnreachableCode);
}
}
} else if (opcode === 226) {
const tableSize = code[ptr + 1] + 1;
if (tableSize === void 0) {
validationError(EOFError.OpcodeIntermediatesOOB);
} else if (tableSize === 0) {
validationError(EOFError.RJUMPVTableSize0);
}
if (ptr + tableSize * 2 + 2 >= code.length) {
validationError(EOFError.OpcodeIntermediatesOOB);
}
const newPc = ptr + 2 + tableSize * 2;
for (let i = 0; i < tableSize; i++) {
const newPtr = ptr + 2 + i * 2;
addIntermediate(newPtr);
addIntermediate(newPtr + 1);
const target = readInt16(code, newPtr) + newPc;
if (target < 0 || target >= code.length) {
validationError(EOFError.OpcodeIntermediatesOOB);
}
successorSet.add(target);
addJump(target);
reachableOpcodes.add(target);
}
addIntermediate(ptr + 1);
ptr += 2 * tableSize + 1;
} else if (opcode === 227 || opcode === 229) {
const target = readUint16(code, ptr + 1);
reachableSections[codeSection].add(target);
if (target >= container.header.codeSizes.length) {
validationError(EOFError.InvalidCallTarget);
}
if (opcode === 227) {
const targetOutputs = container.body.typeSections[target].outputs;
const targetInputs = container.body.typeSections[target].inputs;
if (targetOutputs === 128) {
validationError(EOFError.InvalidCALLFReturning);
}
if (minStackCurrent < targetInputs) {
validationError(EOFError.StackUnderflow);
}
if (maxStackCurrent + container.body.typeSections[target].maxStackHeight - targetInputs > 1024) {
validationError(EOFError.StackOverflow);
}
minStackNext += targetOutputs - targetInputs;
maxStackNext += targetOutputs - targetInputs;
} else {
const currentOutputs = container.body.typeSections[codeSection].outputs;
const targetOutputs = container.body.typeSections[target].outputs;
const targetInputs = container.body.typeSections[target].inputs;
const targetNonReturning = targetOutputs === 128;
if (targetOutputs > currentOutputs && !targetNonReturning) {
validationError(EOFError.InvalidJUMPF);
}
if (returningFunction && targetOutputs <= 127) {
validationError(EOFError.InvalidReturningSection);
}
if (targetNonReturning) {
if (minStackCurrent < targetInputs) {
validationError(EOFError.StackUnderflow);
}
} else {
const expectedStack = currentOutputs + targetInputs - targetOutputs;
if (!(minStackCurrent === maxStackCurrent && maxStackCurrent === expectedStack)) {
validationError(EOFError.InvalidStackHeight);
}
}
if (maxStackCurrent + container.body.typeSections[target].maxStackHeight - targetInputs > 1024) {
validationError(EOFError.StackOverflow);
}
}
} else if (opcode === 228) {
const outputs = container.body.typeSections[codeSection].outputs;
if (!(minStackCurrent === maxStackCurrent && maxStackCurrent === outputs)) {
validationError(EOFError.InvalidStackHeight);
}
} else if (opcode === 230) {
const toDup = code[ptr + 1];
if (toDup + 1 > minStackCurrent) {
validationError(EOFError.StackUnderflow);
}
} else if (opcode === 231) {
const toSwap = code[ptr + 1];
if (toSwap + 1 > minStackCurrent) {
validationError(EOFError.StackUnderflow);
}
} else if (opcode === 232) {
const exchangeRaw = code[ptr + 1];
const n = (exchangeRaw >> 4) + 1;
const m = (exchangeRaw & 15) + 1;
if (n + m + 1 > minStackCurrent) {
validationError(EOFError.StackUnderflow);
}
} else if (opcode === 236) {
const target = code[ptr + 1];
if (target >= container.header.containerSizes.length) {
validationError(EOFError.InvalidEOFCreateTarget);
}
if (containerTypeMap.has(target)) {
if (containerTypeMap.get(target) !== 0) {
validationError(EOFError.ContainerDoubleType);
}
}
containerTypeMap.set(
target,
0
/* InitCode */
);
} else if (opcode === 238) {
if (mode !== 0) {
validationError(EOFError.ContainerTypeError);
}
const target = code[ptr + 1];
if (target >= container.header.containerSizes.length) {
validationError(EOFError.InvalidRETURNContractTarget);
}
if (containerTypeMap.has(target)) {
if (containerTypeMap.get(target) !== 1) {
validationError(EOFError.ContainerDoubleType);
}
}
containerTypeMap.set(
target,
1
/* DeploymentCode */
);
} else if (opcode === 209) {
const dataTarget = readUint16(code, ptr + 1);
const endOfSlice = dataTarget + 32;
if (container.header.dataSize < endOfSlice) {
validationError(EOFError.DataLoadNOutOfBounds);
}
} else if (opcode === 0 || opcode === 243) {
if (mode === 0) {
validationError(EOFError.ContainerTypeError);
}
}
const intermediates = stackDelta[opcode].intermediates;
if (intermediates > 0) {
for (let i = 1; i <= intermediates; i++) {
addIntermediate(ptr + i);
}
ptr += intermediates;
}
if (ptr >= code.length) {
validationError(EOFError.OpcodeIntermediatesOOB);
}
ptr++;
if (stackDelta[opcode].terminating === void 0) {
reachableOpcodes.add(ptr);
if (opcode !== 224) {
successorSet.add(ptr);
}
}
for (const successor of successorSet) {
if (successor < ptr) {
if (stackHeightMin[successor] !== minStackNext || stackHeightMax[successor] !== maxStackNext) {
validationError(EOFError.UnstableStack);
}
}
if (stackHeightMax[successor] === void 0) {
stackHeightMin[successor] = minStackNext;
stackHeightMax[successor] = maxStackNext;
} else {
stackHeightMin[successor] = Math.min(stackHeightMin[successor], minStackNext);
stackHeightMax[successor] = Math.max(stackHeightMax[successor], maxStackNext);
}
}
maxStackHeight = Math.max(maxStackNext, maxStackHeight);
}
if (!terminatingOpcodes.has(lastOpcode)) {
validationError(EOFError.InvalidTerminator);
}
if (container.body.typeSections[codeSection].maxStackHeight !== maxStackHeight) {
validationError(EOFError.MaxStackHeightViolation);
}
if (maxStackHeight > 1023) {
validationError(EOFError.MaxStackHeightLimit);
}
}
const sectionAccumulator = /* @__PURE__ */ new Set();
sectionAccumulator.add(0);
const toCheck = [0];
while (toCheck.length > 0) {
const checkArray = reachableSections[toCheck.pop()];
for (const checkSection of checkArray) {
if (!sectionAccumulator.has(checkSection)) {
sectionAccumulator.add(checkSection);
toCheck.push(checkSection);
}
}
}
if (sectionAccumulator.size !== container.header.codeSizes.length) {
validationError(EOFError.UnreachableCodeSections);
}
if (containerTypeMap.size !== container.header.containerSizes.length) {
validationError(EOFError.UnreachableContainerSections);
}
return containerTypeMap;
}
var EOFContainerMode = /* @__PURE__ */ ((EOFContainerMode2) => {
EOFContainerMode2[EOFContainerMode2["Default"] = 0] = "Default";
EOFContainerMode2[EOFContainerMode2["Initmode"] = 1] = "Initmode";
EOFContainerMode2[EOFContainerMode2["TxInitmode"] = 2] = "TxInitmode";
return EOFContainerMode2;
})(EOFContainerMode || {});
class StreamReader {
// Current pointer to where the stream is being read
constructor(stream) {
this.data = stream;
this.ptr = 0;
}
/**
* Read `amount` bytes from the stream. Throws when trying to read out of bounds with an optional error string.
* This also updates the internal pointer
* @param amount Bytes to read
* @param errorStr Optional error string to throw when trying to read out-of-bounds
* @returns The byte array with length `amount`
*/
readBytes(amount, errorStr) {
const end = this.ptr + amount;
if (end > this.data.length) {
validationError(EOFError.OutOfBounds, this.ptr, errorStr);
}
const ptr = this.ptr;
this.ptr += amount;
return this.data.slice(ptr, end);
}
/**
* Reads an Uint8. Also updates the pointer.
* @param errorStr Optional error string
* @returns The uint8
*/
readUint(errorStr) {
if (this.ptr >= this.data.length) {
validationError(EOFError.OutOfBounds, this.ptr, errorStr);
}
return this.data[this.ptr++];
}
/**
* Verify that the current uint8 pointed to by the pointer is the expected uint8
* Also updates the pointer
* @param expect The uint to expect
* @param errorStr Optional error string when the read uint is not the expected uint
*/
verifyUint(expect, errorStr) {
if (this.readUint() !== expect) {
validationError(EOFError.VerifyUint, this.ptr - 1, errorStr);
}
}
/**
* Same as readUint, except this reads an uint16
* @param errorStr
* @returns
*/
readUint16(errorStr) {
const end = this.ptr + 2;
if (end > this.data.length) {
validationError(EOFError.OutOfBounds, this.ptr, errorStr);
}
const ptr = this.ptr;
this.ptr += 2;
return new DataView(this.data.buffer).getUint16(ptr);
}
/**
* Get the current pointer of the stream
* @returns The pointer
*/
getPtr() {
return this.ptr;
}
// Get the remainder bytes of the current stream
readRemainder() {
return this.data.slice(this.ptr);
}
// Returns `true` if the stream is fully read, or false if there are dangling bytes
isAtEnd() {
return this.ptr === this.data.length;
}
}
class EOFHeader {
// Internal array to track at which byte of the container the code starts (per section)
/**
* Create an EOF header. Performs various validation checks inside the constructor
* @param input either a raw header or a complete container
*/
constructor(input) {
if (input.length > MAX_HEADER_SIZE) {
throw new Error("err: container size more than maximum valid size");
}
const stream = new StreamReader(input);
stream.verifyUint(FORMAT, EOFError.FORMAT);
stream.verifyUint(MAGIC, EOFError.MAGIC);
stream.verifyUint(VERSION, EOFError.VERSION);
if (input.length < 15) {
throw new Error("err: container size less than minimum valid size");
}
stream.verifyUint(KIND_TYPE, EOFError.KIND_TYPE);
const typeSize = stream.readUint16(EOFError.TypeSize);
if (typeSize < TYPE_MIN) {
validationError(EOFError.InvalidTypeSize, typeSize);
}
if (typeSize % TYPE_DIVISOR !== 0) {
validationError(EOFError.InvalidTypeSize, typeSize);
}
if (typeSize > TYPE_MAX) {
throw new Error(`err: number of code sections must not exceed 1024 (got ${typeSize})`);
}
stream.verifyUint(KIND_CODE, EOFError.KIND_CODE);
const codeSize = stream.readUint16(EOFError.CodeSize);
if (codeSize < CODE_MIN) {
validationError(EOFError.MinCodeSections);
}
if (codeSize !== typeSize / TYPE_DIVISOR) {
validationError(EOFError.TypeSections, typeSize / TYPE_DIVISOR, codeSize);
}
const codeSizes = [];
for (let i = 0; i < codeSize; i++) {
const codeSectionSize = stream.readUint16(EOFError.CodeSection);
if (codeSectionSize < CODE_SIZE_MIN) {
validationError(EOFError.CodeSectionSize);
}
codeSizes.push(codeSectionSize);
}
let nextSection = stream.readUint();
const containerSizes = [];
if (nextSection === KIND_CONTAINER) {
const containerSectionSize = stream.readUint16(EOFError.ContainerSize);
if (containerSectionSize < CONTAINER_MIN) {
validationError(EOFError.ContainerSectionSize);
}
if (containerSectionSize > CONTAINER_MAX) {
validationError(EOFError.ContainerSectionSize);
}
for (let i = 0; i < containerSectionSize; i++) {
const containerSize = stream.readUint16(EOFError.ContainerSection);
if (containerSize < CONTAINER_SIZE_MIN) {
validationError(EOFError.ContainerSectionMin);
}
containerSizes.push(containerSize);
}
nextSection = stream.readUint();
}
if (nextSection !== KIND_DATA) {
validationError(EOFError.KIND_DATA);
}
this.dataSizePtr = stream.getPtr();
const dataSize = stream.readUint16(EOFError.DataSize);
stream.verifyUint(TERMINATOR, EOFError.TERMINATOR);
this.typeSize = typeSize;
this.codeSizes = codeSizes;
this.containerSizes = containerSizes;
this.dataSize = dataSize;
this.buffer = input.slice(0, stream.getPtr());
const relativeOffset = this.buffer.length + this.typeSize;
this.codeStartPos = [relativeOffset];
}
sections() {
return [this.typeSize, this.codeSizes, this.containerSizes, this.dataSize];
}
sectionSizes() {
return [1, this.codeSizes.length, this.containerSizes.length, 1];
}
// Returns the code position in the container for the requested section
// Setting the Program Counter in the EVM to a number of this array would start executing the bytecode of the indexed section
getCodePosition(section) {
if (this.codeStartPos[section]) {
return this.codeStartPos[section];
}
const start = this.codeStartPos.length;
let offset = this.codeStartPos[start - 1];
for (let i = start; i <= section; i++) {
offset += this.codeSizes[i - 1];
this.codeStartPos[i] = offset;
}
return offset;
}
}
class EOFBody {
// Only available in TxInitmode. The `txCallData` are the dangling bytes after parsing the container,
// and these are used for the CALLDATA in the EVM when trying to create a contract via a transaction, and the deployment code is an EOF container
constructor(buf, header, eofMode = 0, dataSectionAllowedSmaller = false) {
const stream = new StreamReader(buf);
const typeSections = [];
for (let i = 0; i < header.typeSize / 4; i++) {
const inputs = stream.readUint(EOFError.Inputs);
const outputs = stream.readUint(EOFError.Outputs);
const maxStackHeight = stream.readUint16(EOFError.MaxStackHeight);
if (i === 0) {
if (inputs !== 0) {
validationError(EOFError.Code0Inputs);
}
if (outputs !== 128) {
validationError(EOFError.Code0Outputs);
}
}
if (inputs > INPUTS_MAX) {
validationError(EOFError.MaxInputs, i, inputs);
}
if (outputs > OUTPUTS_MAX) {
validationError(EOFError.MaxOutputs, i, outputs);
}
if (maxStackHeight > MAX_STACK_HEIGHT) {
validationError(EOFError.MaxStackHeightLimit, i, maxStackHeight);
}
typeSections.push({
inputs,
outputs,
maxStackHeight
});
}
const codeStartPtr = stream.getPtr();
const codes = [];
for (const [i, codeSize] of header.codeSizes.entries()) {
try {
const code = stream.readBytes(codeSize);
codes.push(code);
} catch {
validationError(EOFError.CodeSection, i);
}
}
const entireCodeSection = buf.slice(codeStartPtr, stream.getPtr());
const containers = [];
for (const [i, containerSize] of header.containerSizes.entries()) {
try {
const container = stream.readBytes(containerSize);
containers.push(container);
} catch {
validationError(EOFError.ContainerSection, i);
}
}
let dataSection;
if (eofMode !== 1 && !dataSectionAllowedSmaller) {
dataSection = stream.readBytes(header.dataSize, EOFError.DataSection);
if (eofMode === 0) {
if (!stream.isAtEnd()) {
validationError(EOFError.DanglingBytes);
}
} else {
this.txCallData = stream.readRemainder();
}
} else {
dataSection = stream.readRemainder();
}
this.typeSections = typeSections;
this.codeSections = codes;
this.containerSections = containers;
this.entireCode = entireCodeSection;
this.dataSection = dataSection;
this.buffer = buf;
}
sections() {
return [this.typeSections, this.codeSections, this.dataSection];
}
size() {
return {
typeSize: this.typeSections.length,
codeSize: this.codeSections.length,
dataSize: this.dataSection.length
};
}
sectionSizes() {
return [
this.typeSections.map(() => 4),
this.codeSections.map((b) => b.length),
this.dataSection.length
];
}
}
class EOFContainer {
/**
*
* @param buf Entire container buffer
* @param eofMode Container mode to validate the container on
* @param dataSectionAllowedSmaller `true` if the data section is allowed to be smaller than the data section size in the header
*/
constructor(buf, eofMode = 0, dataSectionAllowedSmaller = false) {
this.eofMode = eofMode;
this.header = new EOFHeader(buf);
this.body = new EOFBody(
buf.slice(this.header.buffer.length),
this.header,
eofMode,
dataSectionAllowedSmaller
);
this.buffer = buf;
}
}
function validateEOF(input, evm, containerMode = ContainerSectionType.RuntimeCode, eofMode = 0) {
const container = new EOFContainer(
input,
eofMode,
containerMode === ContainerSectionType.DeploymentCode
);
const containerMap = verifyCode(container, evm, containerMode);
for (let i = 0; i < container.body.containerSections.length; i++) {
const subContainer = container.body.containerSections[i];
const mode = containerMap.get(i);
validateEOF(subContainer, evm, mode);
}
return container;
}
const Mainnet = {
name: "mainnet",
chainId: 1,
defaultHardfork: "cancun",
consensus: {
type: "pow",
algorithm: "ethash",
ethash: {}
},
comment: "The Ethereum main chain",
url: "https://ethstats.net/",
genesis: {
gasLimit: 5e3,
difficulty: 17179869184,
nonce: "0x0000000000000042",
extraData: "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"
},
depositContractAddress: "0x00000000219ab540356cBB839Cbe05303d7705Fa",
hardforks: [
{
name: "chainstart",
block: 0,
forkHash: "0xfc64ec04"
},
{
name: "homestead",
block: 115e4,
forkHash: "0x97c2c34c"
},
{
name: "dao",
block: 192e4,
forkHash: "0x91d1f948"
},
{
name: "tangerineWhistle",
block: 2463e3,
forkHash: "0x7a64da13"
},
{
name: "spuriousDragon",
block: 2675e3,
forkHash: "0x3edd5b10"
},
{
name: "byzantium",
block: 437e4,
forkHash: "0xa00bc324"
},
{
name: "constantinople",
block: 728e4,
forkHash: "0x668db0af"
},
{
name: "petersburg",
block: 728e4,
forkHash: "0x668db0af"
},
{
name: "istanbul",
block: 9069e3,
forkHash: "0x879d6e30"
},
{
name: "muirGlacier",
block: 92e5,
forkHash: "0xe029e991"
},
{
name: "berlin",
block: 12244e3,
forkHash: "0x0eb440f6"
},
{
name: "london",
block: 12965e3,
forkHash: "0xb715077d"
},
{
name: "arrowGlacier",
block: 13773e3,
forkHash: "0x20c327fc"
},
{
name: "grayGlacier",
block: 1505e4,
forkHash: "0xf0afd0e3"
},
{
// The forkHash will remain same as mergeForkIdTransition is post merge
// terminal block: https://etherscan.io/block/15537393
name: "paris",
block: 15537394,
forkHash: "0xf0afd0e3"
},
{
name: "mergeForkIdTransition",
block: null,
forkHash: null
},
{
name: "shanghai",
block: null,
timestamp: "1681338455",
forkHash: "0xdce96c2d"
},
{
name: "cancun",
block: null,
timestamp: "1710338135",
forkHash: "0x9f3d2254"
},
{
name: "prague",
block: null
}
],
bootstrapNodes: [
{
ip: "18.138.108.67",
port: 30303,
id: "d860a01f9722d78051619d1e2351aba3f43f943f6f00718d1b9baa4101932a1f5011f16bb2b1bb35db20d6fe28fa0bf09636d26a87d31de9ec6203eeedb1f666",
location: "ap-southeast-1-001",
comment: "bootnode-aws-ap-southeast-1-001"
},
{
ip: "3.209.45.79",
port: 30303,
id: "22a8232c3abc76a16ae9d6c3b164f98775fe226f0917b0ca871128a74a8e9630b458460865bab457221f1d448dd9791d24c4e5d88786180ac185df813a68d4de",
location: "us-east-1-001",
comment: "bootnode-aws-us-east-1-001"
},
{
ip: "65.108.70.101",
port: 30303,
id: "2b252ab6a1d0f971d9722cb839a42cb81db019ba44c08754628ab4a823487071b5695317c8ccd085219c3a03af063495b2f1da8d18218da2d6a82981b45e6ffc",
location: "eu-west-1-001",
comment: "bootnode-hetzner-hel"
},
{
ip: "157.90.35.166",
port: 30303,
id: "4aeb4ab6c14b23e2c4cfdce879c04b0748a20d8e9b59e25ded2a08143e265c6c25936e74cbc8e641e3312ca288673d91f2f93f8e277de3cfa444ecdaaf982052",
location: "eu-central-1-001",
comment: "bootnode-hetzner-fsn"
}
],
dnsNetworks: [
"enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@all.mainnet.ethdisco.net"
]
};
function number(n) {
if (!Number.isSafeInteger(n) || n < 0)
throw new Error(`positive integer expected, not ${n}`);
}
function bool(b) {
if (typeof b !== "boolean")
throw new Error(`boolean expected, not ${b}`);
}
function isBytes$1(a) {
return a instanceof Uint8Array || a != null && typeof a === "object" && a.constructor.name === "Uint8Array";
}
function bytes(b, ...lengths) {
if (!isBytes$1(b))
throw new Error("Uint8Array expected");
if (lengths.length > 0 && !lengths.includes(b.length))
throw new Error(`Uint8Array expected of length ${lengths}, not of length=${b.length}`);
}
function hash(h) {
if (typeof h !== "function" || typeof h.create !== "function")
throw new Error("Hash should be wrapped by utils.wrapConstructor");
number(h.outputLen);
number(h.blockLen);
}
function exists(instance, checkFinished = true) {
if (instance.destroyed)
throw new Error("Hash instance has been destroyed");
if (checkFinished && instance.finished)
throw new Error("Hash#digest() has already been called");
}
function output(out, instance) {
bytes(out);
const min = instance.outputLen;
if (out.length < min) {
throw new Error(`digestInto() expects output buffer of length at least ${min}`);
}
}
const assert = { number, bool, bytes, hash, exists, output };
const crypto = typeof globalThis === "object" && "crypto" in globalThis ? globalThis.crypto : void 0;
/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
const u32 = (arr) => new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
const createView = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
const rotr = (word, shift) => word << 32 - shift | word >>> shift;
const rotl = (word, shift) => word << shift | word >>> 32 - shift >>> 0;
const isLE = new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68;
const byteSwap = (word) => word << 24 & 4278190080 | word << 8 & 16711680 | word >>> 8 & 65280 | word >>> 24 & 255;
function byteSwap32(arr) {
for (let i = 0; i < arr.length; i++) {
arr[i] = byteSwap(arr[i]);
}
}
const hexes$1 = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
function bytesToHex$3(bytes$1) {
bytes(bytes$1);
let hex = "";
for (let i = 0; i < bytes$1.length; i++) {
hex += hexes$1[bytes$1[i]];
}
return hex;
}
const asciis$1 = { _0: 48, _9: 57, _A: 65, _F: 70, _a: 97, _f: 102 };
function asciiToBase16$1(char) {
if (char >= asciis$1._0 && char <= asciis$1._9)
return char - asciis$1._0;
if (char >= asciis$1._A && char <= asciis$1._F)
return char - (asciis$1._A - 10);
if (char >= asciis$1._a && char <= asciis$1._f)
return char - (asciis$1._a - 10);
return;
}
function hexToBytes$4(hex) {
if (typeof hex !== "string")
throw new Error("hex string expected, got " + typeof hex);
const hl = hex.length;
const al = hl / 2;
if (hl % 2)
throw new Error("padded hex string expected, got unpadded hex of length " + hl);
const array = new Uint8Array(al);
for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
const n1 = asciiToBase16$1(hex.charCodeAt(hi));
const n2 = asciiToBase16$1(hex.charCodeAt(hi + 1));
if (n1 === void 0 || n2 === void 0) {
const char = hex[hi] + hex[hi + 1];
throw new Error('hex string expected, got non-hex character "' + char + '" at index ' + hi);
}
array[ai] = n1 * 16 + n2;
}
return array;
}
function utf8ToBytes$2(str) {
if (typeof str !== "string")
throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
return new Uint8Array(new TextEncoder().encode(str));
}
function toBytes$2(data) {
if (typeof data === "string")
data = utf8ToBytes$2(data);
bytes(data);
return data;
}
function concatBytes$3(...arrays) {
let sum = 0;
for (let i = 0; i < arrays.length; i++) {
const a = arrays[i];
bytes(a);
sum += a.length;
}
const res = new Uint8Array(sum);
for (let i = 0, pad = 0; i < arrays.length; i++) {
const a = arrays[i];
res.set(a, pad);
pad += a.length;
}
return res;
}
class Hash {
// Safe version that clones internal state
clone() {
return this._cloneInto();
}
}
function wrapConstructor(hashCons) {
const hashC = (msg) => hashCons().update(toBytes$2(msg)).digest();
const tmp = hashCons();
hashC.outputLen = tmp.outputLen;
hashC.blockLen = tmp.blockLen;
hashC.create = () => hashCons();
return hashC;
}
function randomBytes(bytesLength = 32) {
if (crypto && typeof crypto.getRandomValues === "function") {
return crypto.getRandomValues(new Uint8Array(bytesLength));
}
if (crypto && typeof crypto.randomBytes === "function") {
return crypto.randomBytes(bytesLength);
}
throw new Error("crypto.getRandomValues must be defined");
}
function setBigUint64(view, byteOffset, value, isLE2) {
if (typeof view.setBigUint64 === "function")
return view.setBigUint64(byteOffset, value, isLE2);
const _32n2 = BigInt(32);
const _u32_max = BigInt(4294967295);
const wh = Number(value >> _32n2 & _u32_max);
const wl = Number(value & _u32_max);
const h = isLE2 ? 4 : 0;
const l = isLE2 ? 0 : 4;
view.setUint32(byteOffset + h, wh, isLE2);
view.setUint32(byteOffset + l, wl, isLE2);
}
const Chi = (a, b, c) => a & b ^ ~a & c;
const Maj = (a, b, c) => a & b ^ a & c ^ b & c;
class HashMD extends Hash {
constructor(blockLen, outputLen, padOffset, isLE2) {
super();
this.blockLen = blockLen;
this.outputLen = outputLen;
this.padOffset = padOffset;
this.isLE = isLE2;
this.finished = false;
this.length = 0;
this.pos = 0;
this.destroyed = false;
this.buffer = new Uint8Array(blockLen);
this.view = createView(this.buffer);
}
update(data) {
exists(this);
const { view, buffer, blockLen } = this;
data = toBytes$2(data);
const len = data.length;
for (let pos = 0; pos < len; ) {
const take = Math.min(blockLen - this.pos, len - pos);
if (take === blockLen) {
const dataView = createView(data);
for (; blockLen <= len - pos; pos += blockLen)
this.process(dataView, pos);
continue;
}
buffer.set(data.subarray(pos, pos + take), this.pos);
this.pos += take;
pos += take;
if (this.pos === blockLen) {
this.process(view, 0);
this.pos = 0;
}
}
this.length += data.length;
this.roundClean();
return this;
}
digestInto(out) {
exists(this);
output(out, this);
this.finished = true;
const { buffer, view, blockLen, isLE: isLE2 } = this;
let { pos } = this;
buffer[pos++] = 128;
this.buffer.subarray(pos).fill(0);
if (this.padOffset > blockLen - pos) {
this.process(view, 0);
pos = 0;
}
for (let i = pos; i < blockLen; i++)
buffer[i] = 0;
setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE2);
this.process(view, 0);
const oview = createView(out);
const len = this.outputLen;
if (len % 4)
throw new Error("_sha2: outputLen should be aligned to 32bit");
const outLen = len / 4;
const state = this.get();
if (outLen > state.length)
throw new Error("_sha2: outputLen bigger than state");
for (let i = 0; i < outLen; i++)
oview.setUint32(4 * i, state[i], isLE2);
}
digest() {
const { buffer, outputLen } = this;
this.digestInto(buffer);
const res = buffer.slice(0, outputLen);
this.destroy();
return res;
}
_cloneInto(to) {
to || (to = new this.constructor());
to.set(...this.get());
const { blockLen, buffer, length, finished, destroyed, pos } = this;
to.length = length;
to.pos = pos;
to.finished = finished;
to.destroyed = destroyed;
if (length % blockLen)
to.buffer.set(buffer);
return to;
}
}
const SHA256_K = /* @__PURE__ */ new Uint32Array([
1116352408,
1899447441,
3049323471,
3921009573,
961987163,
1508970993,
2453635748,
2870763221,
3624381080,
310598401,
607225278,
1426881987,
1925078388,
2162078206,
2614888103,
3248222580,
3835390401,
4022224774,
264347078,
604807628,
770255983,
1249150122,
1555081692,
1996064986,
2554220882,
2821834349,
2952996808,
3210313671,
3336571891,
3584528711,
113926993,
338241895,
666307205,
773529912,
1294757372,
1396182291,
1695183700,
1986661051,
2177026350,
2456956037,
2730485921,
2820302411,
3259730800,
3345764771,
3516065817,
3600352804,
4094571909,
275423344,
430227734,
506948616,
659060556,
883997877,
958139571,
1322822218,
1537002063,
1747873779,
1955562222,
2024104815,
2227730452,
2361852424,
2428436474,
2756734187,
3204031479,
3329325298
]);
const SHA256_IV = /* @__PURE__ */ new Uint32Array([
1779033703,
3144134277,
1013904242,
2773480762,
1359893119,
2600822924,
528734635,
1541459225
]);
const SHA256_W = /* @__PURE__ */ new Uint32Array(64);
class SHA256 extends HashMD {
constructor() {
super(64, 32, 8, false);
this.A = SHA256_IV[0] | 0;
this.B = SHA256_IV[1] | 0;
this.C = SHA256_IV[2] | 0;
this.D = SHA256_IV[3] | 0;
this.E = SHA256_IV[4] | 0;
this.F = SHA256_IV[5] | 0;
this.G = SHA256_IV[6] | 0;
this.H = SHA256_IV[7] | 0;
}
get() {
const { A, B, C, D, E, F: F2, G, H } = this;
return [A, B, C, D, E, F2, G, H];
}
// prettier-ignore
set(A, B, C, D, E, F2, G, H) {
this.A = A | 0;
this.B = B | 0;
this.C = C | 0;
this.D = D | 0;
this.E = E | 0;
this.F = F2 | 0;
this.G = G | 0;
this.H = H | 0;
}
process(view, offset) {
for (let i = 0; i < 16; i++, offset += 4)
SHA256_W[i] = view.getUint32(offset, false);
for (let i = 16; i < 64; i++) {
const W15 = SHA256_W[i - 15];
const W2 = SHA256_W[i - 2];
const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3;
const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10;
SHA256_W[i] = s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16] | 0;
}
let { A, B, C, D, E, F: F2, G, H } = this;
for (let i = 0; i < 64; i++) {
const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
const T1 = H + sigma1 + Chi(E, F2, G) + SHA256_K[i] + SHA256_W[i] | 0;
const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
const T2 = sigma0 + Maj(A, B, C) | 0;
H = G;
G = F2;
F2 = E;
E = D + T1 | 0;
D = C;
C = B;
B = A;
A = T1 + T2 | 0;
}
A = A + this.A | 0;
B = B + this.B | 0;
C = C + this.C | 0;
D = D + this.D | 0;
E = E + this.E | 0;
F2 = F2 + this.F | 0;
G = G + this.G | 0;
H = H + this.H | 0;
this.set(A, B, C, D, E, F2, G, H);
}
roundClean() {
SHA256_W.fill(0);
}
destroy() {
this.set(0, 0, 0, 0, 0, 0, 0, 0);
this.buffer.fill(0);
}
}
const sha256$1 = /* @__PURE__ */ wrapConstructor(() => new SHA256());
class HMAC extends Hash {
constructor(hash$1, _key) {
super();
this.finished = false;
this.destroyed = false;
hash(hash$1);
const key = toBytes$2(_key);
this.iHash = hash$1.create();
if (typeof this.iHash.update !== "function")
throw new Error("Expected instance of class which extends utils.Hash");
this.blockLen = this.iHash.blockLen;
this.outputLen = this.iHash.outputLen;
const blockLen = this.blockLen;
const pad = new Uint8Array(blockLen);
pad.set(key.length > blockLen ? hash$1.create().update(key).digest() : key);
for (let i = 0; i < pad.length; i++)
pad[i] ^= 54;
this.iHash.update(pad);
this.oHash = hash$1.create();
for (let i = 0; i < pad.length; i++)
pad[i] ^= 54 ^ 92;
this.oHash.update(pad);
pad.fill(0);
}
update(buf) {
exists(this);
this.iHash.update(buf);
return this;
}
digestInto(out) {
exists(this);
bytes(out, this.outputLen);
this.finished = true;
this.iHash.digestInto(out);
this.oHash.update(out);
this.oHash.digestInto(out);
this.destroy();
}
digest() {
const out = new Uint8Array(this.oHash.outputLen);
this.digestInto(out);
return out;
}
_cloneInto(to) {
to || (to = Object.create(Object.getPrototypeOf(this), {}));
const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
to = to;
to.finished = finished;
to.destroyed = destroyed;
to.blockLen = blockLen;
to.outputLen = outputLen;
to.oHash = oHash._cloneInto(to.oHash);
to.iHash = iHash._cloneInto(to.iHash);
return to;
}
destroy() {
this.destroyed = true;
this.oHash.destroy();
this.iHash.destroy();
}
}
const hmac = (hash2, key, message) => new HMAC(hash2, key).update(message).digest();
hmac.create = (hash2, key) => new HMAC(hash2, key);
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
const _0n$7 = /* @__PURE__ */ BigInt(0);
const _1n$9 = /* @__PURE__ */ BigInt(1);
const _2n$8 = /* @__PURE__ */ BigInt(2);
function isBytes(a) {
return a instanceof Uint8Array || a != null && typeof a === "object" && a.constructor.name === "Uint8Array";
}
function abytes(item) {
if (!isBytes(item))
throw new Error("Uint8Array expected");
}
function abool(title, value) {
if (typeof value !== "boolean")
throw new Error(`${title} must be valid boolean, got "${value}".`);
}
const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
function bytesToHex$2(bytes2) {
abytes(bytes2);
let hex = "";
for (let i = 0; i < bytes2.length; i++) {
hex += hexes[bytes2[i]];
}
return hex;
}
function numberToHexUnpadded(num) {
const hex = num.toString(16);
return hex.length & 1 ? `0${hex}` : hex;
}
function hexToNumber(hex) {
if (typeof hex !== "string")
throw new Error("hex string expected, got " + typeof hex);
return BigInt(hex === "" ? "0" : `0x${hex}`);
}
const asciis = { _0: 48, _9: 57, _A: 65, _F: 70, _a: 97, _f: 102 };
function asciiToBase16(char) {
if (char >= asciis._0 && char <= asciis._9)
return char - asciis._0;
if (char >= asciis._A && char <= asciis._F)
return char - (asciis._A - 10);
if (char >= asciis._a && char <= asciis._f)
return char - (asciis._a - 10);
return;
}
function hexToBytes$3(hex) {
if (typeof hex !== "string")
throw new Error("hex string expected, got " + typeof hex);
const hl = hex.length;
const al = hl / 2;
if (hl % 2)
throw new Error("padded hex string expected, got unpadded hex of length " + hl);
const array = new Uint8Array(al);
for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
const n1 = asciiToBase16(hex.charCodeAt(hi));
const n2 = asciiToBase16(hex.charCodeAt(hi + 1));
if (n1 === void 0 || n2 === void 0) {
const char = hex[hi] + hex[hi + 1];
throw new Error('hex string expected, got non-hex character "' + char + '" at index ' + hi);
}
array[ai] = n1 * 16 + n2;
}
return array;
}
function bytesToNumberBE(bytes2) {
return hexToNumber(bytesToHex$2(bytes2));
}
function bytesToNumberLE(bytes2) {
abytes(bytes2);
return hexToNumber(bytesToHex$2(Uint8Array.from(bytes2).reverse()));
}
function numberToBytesBE(n, len) {
return hexToBytes$3(n.toString(16).padStart(len * 2, "0"));
}
function numberToBytesLE(n, len) {
return numberToBytesBE(n, len).reverse();
}
function numberToVarBytesBE(n) {
return hexToBytes$3(numberToHexUnpadded(n));
}
function ensureBytes(title, hex, expectedLength) {
let res;
if (typeof hex === "string") {
try {
res = hexToBytes$3(hex);
} catch (e) {
throw new Error(`${title} must be valid hex string, got "${hex}". Cause: ${e}`);
}
} else if (isBytes(hex)) {
res = Uint8Array.from(hex);
} else {
throw new Error(`${title} must be hex string or Uint8Array`);
}
const len = res.length;
if (typeof expectedLength === "number" && len !== expectedLength)
throw new Error(`${title} expected ${expectedLength} bytes, got ${len}`);
return res;
}
function concatBytes$2(...arrays) {
let sum = 0;
for (let i = 0; i < arrays.length; i++) {
const a = arrays[i];
abytes(a);
sum += a.length;
}
const res = new Uint8Array(sum);
for (let i = 0, pad = 0; i < arrays.length; i++) {
const a = arrays[i];
res.set(a, pad);
pad += a.length;
}
return res;
}
function equalBytes(a, b) {
if (a.length !== b.length)
return false;
let diff = 0;
for (let i = 0; i < a.length; i++)
diff |= a[i] ^ b[i];
return diff === 0;
}
function utf8ToBytes$1(str) {
if (typeof str !== "string")
throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
return new Uint8Array(new TextEncoder().encode(str));
}
const isPosBig = (n) => typeof n === "bigint" && _0n$7 <= n;
function inRange(n, min, max) {
return isPosBig(n) && isPosBig(min) && isPosBig(max) && min <= n && n < max;
}
function aInRange(title, n, min, max) {
if (!inRange(n, min, max))
throw new Error(`expected valid ${title}: ${min} <= n < ${max}, got ${typeof n} ${n}`);
}
function bitLen(n) {
let len;
for (len = 0; n > _0n$7; n >>= _1n$9, len += 1)
;
return len;
}
function bitGet(n, pos) {
return n >> BigInt(pos) & _1n$9;
}
function bitSet(n, pos, value) {
return n | (value ? _1n$9 : _0n$7) << BigInt(pos);
}
const bitMask = (n) => (_2n$8 << BigInt(n - 1)) - _1n$9;
const u8n = (data) => new Uint8Array(data);
const u8fr = (arr) => Uint8Array.from(arr);
function createHmacDrbg(hashLen, qByteLen, hmacFn) {
if (typeof hashLen !== "number" || hashLen < 2)
throw new Error("hashLen must be a number");
if (typeof qByteLen !== "number" || qByteLen < 2)
throw new Error("qByteLen must be a number");
if (typeof hmacFn !== "function")
throw new Error("hmacFn must be a function");
let v = u8n(hashLen);
let k = u8n(hashLen);
let i = 0;
const reset = () => {
v.fill(1);
k.fill(0);
i = 0;
};
const h = (...b) => hmacFn(k, v, ...b);
const reseed = (seed = u8n()) => {
k = h(u8fr([0]), seed);
v = h();
if (seed.length === 0)
return;
k = h(u8fr([1]), seed);
v = h();
};
const gen2 = () => {
if (i++ >= 1e3)
throw new Error("drbg: tried 1000 values");
let len = 0;
const out = [];
while (len < qByteLen) {
v = h();
const sl = v.slice();
out.push(sl);
len += v.length;
}
return concatBytes$2(...out);
};
const genUntil = (seed, pred) => {
reset();
reseed(seed);
let res = void 0;
while (!(res = pred(gen2())))
reseed();
reset();
return res;
};
return genUntil;
}
const validatorFns = {
bigint: (val) => typeof val === "bigint",
function: (val) => typeof val === "function",
boolean: (val) => typeof val === "boolean",
string: (val) => typeof val === "string",
stringOrUint8Array: (val) => typeof val === "string" || isBytes(val),
isSafeInteger: (val) => Number.isSafeInteger(val),
array: (val) => Array.isArray(val),
field: (val, object) => object.Fp.isValid(val),
hash: (val) => typeof val === "function" && Number.isSafeInteger(val.outputLen)
};
function validateObject(object, validators, optValidators = {}) {
const checkField = (fieldName, type, isOptional) => {
const checkVal = validatorFns[type];
if (typeof checkVal !== "function")
throw new Error(`Invalid validator "${type}", expected function`);
const val = object[fieldName];
if (isOptional && val === void 0)
return;
if (!checkVal(val, object)) {
throw new Error(`Invalid param ${String(fieldName)}=${val} (${typeof val}), expected ${type}`);
}
};
for (const [fieldName, type] of Object.entries(validators))
checkField(fieldName, type, false);
for (const [fieldName, type] of Object.entries(optValidators))
checkField(fieldName, type, true);
return object;
}
const notImplemented = () => {
throw new Error("not implemented");
};
function memoized(fn) {
const map = /* @__PURE__ */ new WeakMap();
return (arg, ...args) => {
const val = map.get(arg);
if (val !== void 0)
return val;
const computed = fn(arg, ...args);
map.set(arg, computed);
return computed;
};
}
const ut = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
__proto__: null,
aInRange,
abool,
abytes,
bitGet,
bitLen,
bitMask,
bitSet,
bytesToHex: bytesToHex$2,
bytesToNumberBE,
bytesToNumberLE,
concatBytes: concatBytes$2,
createHmacDrbg,
ensureBytes,
equalBytes,
hexToBytes: hexToBytes$3,
hexToNumber,
inRange,
isBytes,
memoized,
notImplemented,
numberToBytesBE,
numberToBytesLE,
numberToHexUnpadded,
numberToVarBytesBE,
utf8ToBytes: utf8ToBytes$1,
validateObject
}, Symbol.toStringTag, { value: "Module" }));
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
const _0n$6 = BigInt(0), _1n$8 = BigInt(1), _2n$7 = BigInt(2), _3n$5 = BigInt(3);
const _4n$2 = BigInt(4), _5n = BigInt(5), _8n = BigInt(8);
BigInt(9);
BigInt(16);
function mod$1(a, b) {
const result = a % b;
return result >= _0n$6 ? result : b + result;
}
function pow(num, power, modulo) {
if (modulo <= _0n$6 || power < _0n$6)
throw new Error("Expected power/modulo > 0");
if (modulo === _1n$8)
return _0n$6;
let res = _1n$8;
while (power > _0n$6) {
if (power & _1n$8)
res = res * num % modulo;
num = num * num % modulo;
power >>= _1n$8;
}
return res;
}
function pow2(x, power, modulo) {
let res = x;
while (power-- > _0n$6) {
res *= res;
res %= modulo;
}
return res;
}
function invert(number2, modulo) {
if (number2 === _0n$6 || modulo <= _0n$6) {
throw new Error(`invert: expected positive integers, got n=${number2} mod=${modulo}`);
}
let a = mod$1(number2, modulo);
let b = modulo;
let x = _0n$6, u = _1n$8;
while (a !== _0n$6) {
const q = b / a;
const r = b % a;
const m = x - u * q;
b = a, a = r, x = u, u = m;
}
const gcd = b;
if (gcd !== _1n$8)
throw new Error("invert: does not exist");
return mod$1(x, modulo);
}
function tonelliShanks(P) {
const legendreC = (P - _1n$8) / _2n$7;
let Q, S, Z;
for (Q = P - _1n$8, S = 0; Q % _2n$7 === _0n$6; Q /= _2n$7, S++)
;
for (Z = _2n$7; Z < P && pow(Z, legendreC, P) !== P - _1n$8; Z++)
;
if (S === 1) {
const p1div4 = (P + _1n$8) / _4n$2;
return function tonelliFast(Fp3, n) {
const root = Fp3.pow(n, p1div4);
if (!Fp3.eql(Fp3.sqr(root), n))
throw new Error("Cannot find square root");
return root;
};
}
const Q1div2 = (Q + _1n$8) / _2n$7;
return function tonelliSlow(Fp3, n) {
if (Fp3.pow(n, legendreC) === Fp3.neg(Fp3.ONE))
throw new Error("Cannot find square root");
let r = S;
let g = Fp3.pow(Fp3.mul(Fp3.ONE, Z), Q);
let x = Fp3.pow(n, Q1div2);
let b = Fp3.pow(n, Q);
while (!Fp3.eql(b, Fp3.ONE)) {
if (Fp3.eql(b, Fp3.ZERO))
return Fp3.ZERO;
let m = 1;
for (let t2 = Fp3.sqr(b); m < r; m++) {
if (Fp3.eql(t2, Fp3.ONE))
break;
t2 = Fp3.sqr(t2);
}
const ge = Fp3.pow(g, _1n$8 << BigInt(r - m - 1));
g = Fp3.sqr(ge);
x = Fp3.mul(x, ge);
b = Fp3.mul(b, g);
r = m;
}
return x;
};
}
function FpSqrt(P) {
if (P % _4n$2 === _3n$5) {
const p1div4 = (P + _1n$8) / _4n$2;
return function sqrt3mod4(Fp3, n) {
const root = Fp3.pow(n, p1div4);
if (!Fp3.eql(Fp3.sqr(root), n))
throw new Error("Cannot find square root");
return root;
};
}
if (P % _8n === _5n) {
const c1 = (P - _5n) / _8n;
return function sqrt5mod8(Fp3, n) {
const n2 = Fp3.mul(n, _2n$7);
const v = Fp3.pow(n2, c1);
const nv = Fp3.mul(n, v);
const i = Fp3.mul(Fp3.mul(nv, _2n$7), v);
const root = Fp3.mul(nv, Fp3.sub(i, Fp3.ONE));
if (!Fp3.eql(Fp3.sqr(root), n))
throw new Error("Cannot find square root");
return root;
};
}
return tonelliShanks(P);
}
const FIELD_FIELDS = [
"create",
"isValid",
"is0",
"neg",
"inv",
"sqrt",
"sqr",
"eql",
"add",
"sub",
"mul",
"pow",
"div",
"addN",
"subN",
"mulN",
"sqrN"
];
function validateField(field) {
const initial = {
ORDER: "bigint",
MASK: "bigint",
BYTES: "isSafeInteger",
BITS: "isSafeInteger"
};
const opts = FIELD_FIELDS.reduce((map, val) => {
map[val] = "function";
return map;
}, initial);
return validateObject(field, opts);
}
function FpPow(f2, num, power) {
if (power < _0n$6)
throw new Error("Expected power > 0");
if (power === _0n$6)
return f2.ONE;
if (power === _1n$8)
return num;
let p = f2.ONE;
let d = num;
while (power > _0n$6) {
if (power & _1n$8)
p = f2.mul(p, d);
d = f2.sqr(d);
power >>= _1n$8;
}
return p;
}
function FpInvertBatch(f2, nums) {
const tmp = new Array(nums.length);
const lastMultiplied = nums.reduce((acc, num, i) => {
if (f2.is0(num))
return acc;
tmp[i] = acc;
return f2.mul(acc, num);
}, f2.ONE);
const inverted = f2.inv(lastMultiplied);
nums.reduceRight((acc, num, i) => {
if (f2.is0(num))
return acc;
tmp[i] = f2.mul(acc, tmp[i]);
return f2.mul(acc, num);
}, inverted);
return tmp;
}
function FpLegendre(order) {
const legendreConst = (order - _1n$8) / _2n$7;
return (f2, x) => f2.pow(x, legendreConst);
}
function nLength(n, nBitLength) {
const _nBitLength = nBitLength !== void 0 ? nBitLength : n.toString(2).length;
const nByteLength = Math.ceil(_nBitLength / 8);
return { nBitLength: _nBitLength, nByteLength };
}
function Field(ORDER, bitLen2, isLE2 = false, redef = {}) {
if (ORDER <= _0n$6)
throw new Error(`Expected Field ORDER > 0, got ${ORDER}`);
const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen2);
if (BYTES > 2048)
throw new Error("Field lengths over 2048 bytes are not supported");
const sqrtP = FpSqrt(ORDER);
const f2 = Object.freeze({
ORDER,
BITS,
BYTES,
MASK: bitMask(BITS),
ZERO: _0n$6,
ONE: _1n$8,
create: (num) => mod$1(num, ORDER),
isValid: (num) => {
if (typeof num !== "bigint")
throw new Error(`Invalid field element: expected bigint, got ${typeof num}`);
return _0n$6 <= num && num < ORDER;
},
is0: (num) => num === _0n$6,
isOdd: (num) => (num & _1n$8) === _1n$8,
neg: (num) => mod$1(-num, ORDER),
eql: (lhs, rhs) => lhs === rhs,
sqr: (num) => mod$1(num * num, ORDER),
add: (lhs, rhs) => mod$1(lhs + rhs, ORDER),
sub: (lhs, rhs) => mod$1(lhs - rhs, ORDER),
mul: (lhs, rhs) => mod$1(lhs * rhs, ORDER),
pow: (num, power) => FpPow(f2, num, power),
div: (lhs, rhs) => mod$1(lhs * invert(rhs, ORDER), ORDER),
// Same as above, but doesn't normalize
sqrN: (num) => num * num,
addN: (lhs, rhs) => lhs + rhs,
subN: (lhs, rhs) => lhs - rhs,
mulN: (lhs, rhs) => lhs * rhs,
inv: (num) => invert(num, ORDER),
sqrt: redef.sqrt || ((n) => sqrtP(f2, n)),
invertBatch: (lst) => FpInvertBatch(f2, lst),
// TODO: do we really need constant cmov?
// We don't have const-time bigints anyway, so probably will be not very useful
cmov: (a, b, c) => c ? b : a,
toBytes: (num) => isLE2 ? numberToBytesLE(num, BYTES) : numberToBytesBE(num, BYTES),
fromBytes: (bytes2) => {
if (bytes2.length !== BYTES)
throw new Error(`Fp.fromBytes: expected ${BYTES}, got ${bytes2.length}`);
return isLE2 ? bytesToNumberLE(bytes2) : bytesToNumberBE(bytes2);
}
});
return Object.freeze(f2);
}
function getFieldBytesLength(fieldOrder) {
if (typeof fieldOrder !== "bigint")
throw new Error("field order must be bigint");
const bitLength = fieldOrder.toString(2).length;
return Math.ceil(bitLength / 8);
}
function getMinHashLength(fieldOrder) {
const length = getFieldBytesLength(fieldOrder);
return length + Math.ceil(length / 2);
}
function mapHashToField(key, fieldOrder, isLE2 = false) {
const len = key.length;
const fieldLen = getFieldBytesLength(fieldOrder);
const minLen = getMinHashLength(fieldOrder);
if (len < 16 || len < minLen || len > 1024)
throw new Error(`expected ${minLen}-1024 bytes of input, got ${len}`);
const num = isLE2 ? bytesToNumberBE(key) : bytesToNumberLE(key);
const reduced = mod$1(num, fieldOrder - _1n$8) + _1n$8;
return isLE2 ? numberToBytesLE(reduced, fieldLen) : numberToBytesBE(reduced, fieldLen);
}
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
const _0n$5 = BigInt(0);
const _1n$7 = BigInt(1);
const pointPrecomputes = /* @__PURE__ */ new WeakMap();
const pointWindowSizes = /* @__PURE__ */ new WeakMap();
function wNAF(c, bits) {
const constTimeNegate = (condition, item) => {
const neg = item.negate();
return condition ? neg : item;
};
const validateW = (W) => {
if (!Number.isSafeInteger(W) || W <= 0 || W > bits)
throw new Error(`Wrong window size=${W}, should be [1..${bits}]`);
};
const opts = (W) => {
validateW(W);
const windows = Math.ceil(bits / W) + 1;
const windowSize = 2 ** (W - 1);
return { windows, windowSize };
};
return {
constTimeNegate,
// non-const time multiplication ladder
unsafeLadder(elm, n) {
let p = c.ZERO;
let d = elm;
while (n > _0n$5) {
if (n & _1n$7)
p = p.add(d);
d = d.double();
n >>= _1n$7;
}
return p;
},
/**
* Creates a wNAF precomputation window. Used for caching.
* Default window size is set by `utils.precompute()` and is equal to 8.
* Number of precomputed points depends on the curve size:
* 2^(𝑊−1) * (Math.ceil(𝑛 / 𝑊) + 1), where:
* - 𝑊 is the window size
* - 𝑛 is the bitlength of the curve order.
* For a 256-bit curve and window size 8, the number of precomputed points is 128 * 33 = 4224.
* @returns precomputed point tables flattened to a single array
*/
precomputeWindow(elm, W) {
const { windows, windowSize } = opts(W);
const points = [];
let p = elm;
let base = p;
for (let window2 = 0; window2 < windows; window2++) {
base = p;
points.push(base);
for (let i = 1; i < windowSize; i++) {
base = base.add(p);
points.push(base);
}
p = base.double();
}
return points;
},
/**
* Implements ec multiplication using precomputed tables and w-ary non-adjacent form.
* @param W window size
* @param precomputes precomputed tables
* @param n scalar (we don't check here, but should be less than curve order)
* @returns real and fake (for const-time) points
*/
wNAF(W, precomputes, n) {
const { windows, windowSize } = opts(W);
let p = c.ZERO;
let f2 = c.BASE;
const mask = BigInt(2 ** W - 1);
const maxNumber = 2 ** W;
const shiftBy = BigInt(W);
for (let window2 = 0; window2 < windows; window2++) {
const offset = window2 * windowSize;
let wbits = Number(n & mask);
n >>= shiftBy;
if (wbits > windowSize) {
wbits -= maxNumber;
n += _1n$7;
}
const offset1 = offset;
const offset2 = offset + Math.abs(wbits) - 1;
const cond1 = window2 % 2 !== 0;
const cond2 = wbits < 0;
if (wbits === 0) {
f2 = f2.add(constTimeNegate(cond1, precomputes[offset1]));
} else {
p = p.add(constTimeNegate(cond2, precomputes[offset2]));
}
}
return { p, f: f2 };
},
wNAFCached(P, n, transform) {
const W = pointWindowSizes.get(P) || 1;
let comp = pointPrecomputes.get(P);
if (!comp) {
comp = this.precomputeWindow(P, W);
if (W !== 1)
pointPrecomputes.set(P, transform(comp));
}
return this.wNAF(W, comp, n);
},
// We calculate precomputes for elliptic curve point multiplication
// using windowed method. This specifies window size and
// stores precomputed values. Usually only base point would be precomputed.
setWindowSize(P, W) {
validateW(W);
pointWindowSizes.set(P, W);
pointPrecomputes.delete(P);
}
};
}
function pippenger(c, field, points, scalars) {
if (!Array.isArray(points) || !Array.isArray(scalars) || scalars.length !== points.length)
throw new Error("arrays of points and scalars must have equal length");
scalars.forEach((s, i) => {
if (!field.isValid(s))
throw new Error(`wrong scalar at index ${i}`);
});
points.forEach((p, i) => {
if (!(p instanceof c))
throw new Error(`wrong point at index ${i}`);
});
const wbits = bitLen(BigInt(points.length));
const windowSize = wbits > 12 ? wbits - 3 : wbits > 4 ? wbits - 2 : wbits ? 2 : 1;
const MASK = (1 << windowSize) - 1;
const buckets = new Array(MASK + 1).fill(c.ZERO);
const lastBits = Math.floor((field.BITS - 1) / windowSize) * windowSize;
let sum = c.ZERO;
for (let i = lastBits; i >= 0; i -= windowSize) {
buckets.fill(c.ZERO);
for (let j = 0; j < scalars.length; j++) {
const scalar = scalars[j];
const wbits2 = Number(scalar >> BigInt(i) & BigInt(MASK));
buckets[wbits2] = buckets[wbits2].add(points[j]);
}
let resI = c.ZERO;
for (let j = buckets.length - 1, sumI = c.ZERO; j > 0; j--) {
sumI = sumI.add(buckets[j]);
resI = resI.add(sumI);
}
sum = sum.add(resI);
if (i !== 0)
for (let j = 0; j < windowSize; j++)
sum = sum.double();
}
return sum;
}
function validateBasic(curve) {
validateField(curve.Fp);
validateObject(curve, {
n: "bigint",
h: "bigint",
Gx: "field",
Gy: "field"
}, {
nBitLength: "isSafeInteger",
nByteLength: "isSafeInteger"
});
return Object.freeze({
...nLength(curve.n, curve.nBitLength),
...curve,
...{ p: curve.Fp.ORDER }
});
}
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
function validateSigVerOpts(opts) {
if (opts.lowS !== void 0)
abool("lowS", opts.lowS);
if (opts.prehash !== void 0)
abool("prehash", opts.prehash);
}
function validatePointOpts(curve) {
const opts = validateBasic(curve);
validateObject(opts, {
a: "field",
b: "field"
}, {
allowedPrivateKeyLengths: "array",
wrapPrivateKey: "boolean",
isTorsionFree: "function",
clearCofactor: "function",
allowInfinityPoint: "boolean",
fromBytes: "function",
toBytes: "function"
});
const { endo, Fp: Fp3, a } = opts;
if (endo) {
if (!Fp3.eql(a, Fp3.ZERO)) {
throw new Error("Endomorphism can only be defined for Koblitz curves that have a=0");
}
if (typeof endo !== "object" || typeof endo.beta !== "bigint" || typeof endo.splitScalar !== "function") {
throw new Error("Expected endomorphism with beta: bigint and splitScalar: function");
}
}
return Object.freeze({ ...opts });
}
const { bytesToNumberBE: b2n, hexToBytes: h2b } = ut;
const DER = {
// asn.1 DER encoding utils
Err: class DERErr extends Error {
constructor(m = "") {
super(m);
}
},
// Basic building block is TLV (Tag-Length-Value)
_tlv: {
encode: (tag, data) => {
const { Err: E } = DER;
if (tag < 0 || tag > 256)
throw new E("tlv.encode: wrong tag");
if (data.length & 1)
throw new E("tlv.encode: unpadded data");
const dataLen = data.length / 2;
const len = numberToHexUnpadded(dataLen);
if (len.length / 2 & 128)
throw new E("tlv.encode: long form length too big");
const lenLen = dataLen > 127 ? numberToHexUnpadded(len.length / 2 | 128) : "";
return `${numberToHexUnpadded(tag)}${lenLen}${len}${data}`;
},
// v - value, l - left bytes (unparsed)
decode(tag, data) {
const { Err: E } = DER;
let pos = 0;
if (tag < 0 || tag > 256)
throw new E("tlv.encode: wrong tag");
if (data.length < 2 || data[pos++] !== tag)
throw new E("tlv.decode: wrong tlv");
const first = data[pos++];
const isLong = !!(first & 128);
let length = 0;
if (!isLong)
length = first;
else {
const lenLen = first & 127;
if (!lenLen)
throw new E("tlv.decode(long): indefinite length not supported");
if (lenLen > 4)
throw new E("tlv.decode(long): byte length is too big");
const lengthBytes = data.subarray(pos, pos + lenLen);
if (lengthBytes.length !== lenLen)
throw new E("tlv.decode: length bytes not complete");
if (lengthBytes[0] === 0)
throw new E("tlv.decode(long): zero leftmost byte");
for (const b of lengthBytes)
length = length << 8 | b;
pos += lenLen;
if (length < 128)
throw new E("tlv.decode(long): not minimal encoding");
}
const v = data.subarray(pos, pos + length);
if (v.length !== length)
throw new E("tlv.decode: wrong value length");
return { v, l: data.subarray(pos + length) };
}
},
// https://crypto.stackexchange.com/a/57734 Leftmost bit of first byte is 'negative' flag,
// since we always use positive integers here. It must always be empty:
// - add zero byte if exists
// - if next byte doesn't have a flag, leading zero is not allowed (minimal encoding)
_int: {
encode(num) {
const { Err: E } = DER;
if (num < _0n$4)
throw new E("integer: negative integers are not allowed");
let hex = numberToHexUnpadded(num);
if (Number.parseInt(hex[0], 16) & 8)
hex = "00" + hex;
if (hex.length & 1)
throw new E("unexpected assertion");
return hex;
},
decode(data) {
const { Err: E } = DER;
if (data[0] & 128)
throw new E("Invalid signature integer: negative");
if (data[0] === 0 && !(data[1] & 128))
throw new E("Invalid signature integer: unnecessary leading zero");
return b2n(data);
}
},
toSig(hex) {
const { Err: E, _int: int, _tlv: tlv } = DER;
const data = typeof hex === "string" ? h2b(hex) : hex;
abytes(data);
const { v: seqBytes, l: seqLeftBytes } = tlv.decode(48, data);
if (seqLeftBytes.length)
throw new E("Invalid signature: left bytes after parsing");
const { v: rBytes, l: rLeftBytes } = tlv.decode(2, seqBytes);
const { v: sBytes, l: sLeftBytes } = tlv.decode(2, rLeftBytes);
if (sLeftBytes.length)
throw new E("Invalid signature: left bytes after parsing");
return { r: int.decode(rBytes), s: int.decode(sBytes) };
},
hexFromSig(sig) {
const { _tlv: tlv, _int: int } = DER;
const seq = `${tlv.encode(2, int.encode(sig.r))}${tlv.encode(2, int.encode(sig.s))}`;
return tlv.encode(48, seq);
}
};
const _0n$4 = BigInt(0), _1n$6 = BigInt(1), _2n$6 = BigInt(2), _3n$4 = BigInt(3), _4n$1 = BigInt(4);
function weierstrassPoints(opts) {
const CURVE = validatePointOpts(opts);
const { Fp: Fp3 } = CURVE;
const Fn = Field(CURVE.n, CURVE.nBitLength);
const toBytes2 = CURVE.toBytes || ((_c, point, _isCompressed) => {
const a = point.toAffine();
return concatBytes$2(Uint8Array.from([4]), Fp3.toBytes(a.x), Fp3.toBytes(a.y));
});
const fromBytes = CURVE.fromBytes || ((bytes2) => {
const tail = bytes2.subarray(1);
const x = Fp3.fromBytes(tail.subarray(0, Fp3.BYTES));
const y = Fp3.fromBytes(tail.subarray(Fp3.BYTES, 2 * Fp3.BYTES));
return { x, y };
});
function weierstrassEquation(x) {
const { a, b } = CURVE;
const x2 = Fp3.sqr(x);
const x3 = Fp3.mul(x2, x);
return Fp3.add(Fp3.add(x3, Fp3.mul(x, a)), b);
}
if (!Fp3.eql(Fp3.sqr(CURVE.Gy), weierstrassEquation(CURVE.Gx)))
throw new Error("bad generator point: equation left != right");
function isWithinCurveOrder(num) {
return inRange(num, _1n$6, CURVE.n);
}
function normPrivateKeyToScalar(key) {
const { allowedPrivateKeyLengths: lengths, nByteLength, wrapPrivateKey, n: N2 } = CURVE;
if (lengths && typeof key !== "bigint") {
if (isBytes(key))
key = bytesToHex$2(key);
if (typeof key !== "string" || !lengths.includes(key.length))
throw new Error("Invalid key");
key = key.padStart(nByteLength * 2, "0");
}
let num;
try {
num = typeof key === "bigint" ? key : bytesToNumberBE(ensureBytes("private key", key, nByteLength));
} catch (error) {
throw new Error(`private key must be ${nByteLength} bytes, hex or bigint, not ${typeof key}`);
}
if (wrapPrivateKey)
num = mod$1(num, N2);
aInRange("private key", num, _1n$6, N2);
return num;
}
function assertPrjPoint(other) {
if (!(other instanceof Point))
throw new Error("ProjectivePoint expected");
}
const toAffineMemo = memoized((p, iz) => {
const { px: x, py: y, pz: z } = p;
if (Fp3.eql(z, Fp3.ONE))
return { x, y };
const is0 = p.is0();
if (iz == null)
iz = is0 ? Fp3.ONE : Fp3.inv(z);
const ax = Fp3.mul(x, iz);
const ay = Fp3.mul(y, iz);
const zz = Fp3.mul(z, iz);
if (is0)
return { x: Fp3.ZERO, y: Fp3.ZERO };
if (!Fp3.eql(zz, Fp3.ONE))
throw new Error("invZ was invalid");
return { x: ax, y: ay };
});
const assertValidMemo = memoized((p) => {
if (p.is0()) {
if (CURVE.allowInfinityPoint && !Fp3.is0(p.py))
return;
throw new Error("bad point: ZERO");
}
const { x, y } = p.toAffine();
if (!Fp3.isValid(x) || !Fp3.isValid(y))
throw new Error("bad point: x or y not FE");
const left = Fp3.sqr(y);
const right = weierstrassEquation(x);
if (!Fp3.eql(left, right))
throw new Error("bad point: equation left != right");
if (!p.isTorsionFree())
throw new Error("bad point: not in prime-order subgroup");
return true;
});
class Point {
constructor(px, py, pz) {
this.px = px;
this.py = py;
this.pz = pz;
if (px == null || !Fp3.isValid(px))
throw new Error("x required");
if (py == null || !Fp3.isValid(py))
throw new Error("y required");
if (pz == null || !Fp3.isValid(pz))
throw new Error("z required");
Object.freeze(this);
}
// Does not validate if the point is on-curve.
// Use fromHex instead, or call assertValidity() later.
static fromAffine(p) {
const { x, y } = p || {};
if (!p || !Fp3.isValid(x) || !Fp3.isValid(y))
throw new Error("invalid affine point");
if (p instanceof Point)
throw new Error("projective point not allowed");
const is0 = (i) => Fp3.eql(i, Fp3.ZERO);
if (is0(x) && is0(y))
return Point.ZERO;
return new Point(x, y, Fp3.ONE);
}
get x() {
return this.toAffine().x;
}
get y() {
return this.toAffine().y;
}
/**
* Takes a bunch of Projective Points but executes only one
* inversion on all of them. Inversion is very slow operation,
* so this improves performance massively.
* Optimization: converts a list of projective points to a list of identical points with Z=1.
*/
static normalizeZ(points) {
const toInv = Fp3.invertBatch(points.map((p) => p.pz));
return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
}
/**
* Converts hash string or Uint8Array to Point.
* @param hex short/long ECDSA hex
*/
static fromHex(hex) {
const P = Point.fromAffine(fromBytes(ensureBytes("pointHex", hex)));
P.assertValidity();
return P;
}
// Multiplies generator point by privateKey.
static fromPrivateKey(privateKey) {
return Point.BASE.multiply(normPrivateKeyToScalar(privateKey));
}
// Multiscalar Multiplication
static msm(points, scalars) {
return pippenger(Point, Fn, points, scalars);
}
// "Private method", don't use it directly
_setWindowSize(windowSize) {
wnaf.setWindowSize(this, windowSize);
}
// A point on curve is valid if it conforms to equation.
assertValidity() {
assertValidMemo(this);
}
hasEvenY() {
const { y } = this.toAffine();
if (Fp3.isOdd)
return !Fp3.isOdd(y);
throw new Error("Field doesn't support isOdd");
}
/**
* Compare one point to another.
*/
equals(other) {
assertPrjPoint(other);
const { px: X1, py: Y1, pz: Z1 } = this;
const { px: X2, py: Y2, pz: Z2 } = other;
const U1 = Fp3.eql(Fp3.mul(X1, Z2), Fp3.mul(X2, Z1));
const U2 = Fp3.eql(Fp3.mul(Y1, Z2), Fp3.mul(Y2, Z1));
return U1 && U2;
}
/**
* Flips point to one corresponding to (x, -y) in Affine coordinates.
*/
negate() {
return new Point(this.px, Fp3.neg(this.py), this.pz);
}
// Renes-Costello-Batina exception-free doubling formula.
// There is 30% faster Jacobian formula, but it is not complete.
// https://eprint.iacr.org/2015/1060, algorithm 3
// Cost: 8M + 3S + 3*a + 2*b3 + 15add.
double() {
const { a, b } = CURVE;
const b3 = Fp3.mul(b, _3n$4);
const { px: X1, py: Y1, pz: Z1 } = this;
let X3 = Fp3.ZERO, Y3 = Fp3.ZERO, Z3 = Fp3.ZERO;
let t0 = Fp3.mul(X1, X1);
let t1 = Fp3.mul(Y1, Y1);
let t2 = Fp3.mul(Z1, Z1);
let t3 = Fp3.mul(X1, Y1);
t3 = Fp3.add(t3, t3);
Z3 = Fp3.mul(X1, Z1);
Z3 = Fp3.add(Z3, Z3);
X3 = Fp3.mul(a, Z3);
Y3 = Fp3.mul(b3, t2);
Y3 = Fp3.add(X3, Y3);
X3 = Fp3.sub(t1, Y3);
Y3 = Fp3.add(t1, Y3);
Y3 = Fp3.mul(X3, Y3);
X3 = Fp3.mul(t3, X3);
Z3 = Fp3.mul(b3, Z3);
t2 = Fp3.mul(a, t2);
t3 = Fp3.sub(t0, t2);
t3 = Fp3.mul(a, t3);
t3 = Fp3.add(t3, Z3);
Z3 = Fp3.add(t0, t0);
t0 = Fp3.add(Z3, t0);
t0 = Fp3.add(t0, t2);
t0 = Fp3.mul(t0, t3);
Y3 = Fp3.add(Y3, t0);
t2 = Fp3.mul(Y1, Z1);
t2 = Fp3.add(t2, t2);
t0 = Fp3.mul(t2, t3);
X3 = Fp3.sub(X3, t0);
Z3 = Fp3.mul(t2, t1);
Z3 = Fp3.add(Z3, Z3);
Z3 = Fp3.add(Z3, Z3);
return new Point(X3, Y3, Z3);
}
// Renes-Costello-Batina exception-free addition formula.
// There is 30% faster Jacobian formula, but it is not complete.
// https://eprint.iacr.org/2015/1060, algorithm 1
// Cost: 12M + 0S + 3*a + 3*b3 + 23add.
add(other) {
assertPrjPoint(other);
const { px: X1, py: Y1, pz: Z1 } = this;
const { px: X2, py: Y2, pz: Z2 } = other;
let X3 = Fp3.ZERO, Y3 = Fp3.ZERO, Z3 = Fp3.ZERO;
const a = CURVE.a;
const b3 = Fp3.mul(CURVE.b, _3n$4);
let t0 = Fp3.mul(X1, X2);
let t1 = Fp3.mul(Y1, Y2);
let t2 = Fp3.mul(Z1, Z2);
let t3 = Fp3.add(X1, Y1);
let t4 = Fp3.add(X2, Y2);
t3 = Fp3.mul(t3, t4);
t4 = Fp3.add(t0, t1);
t3 = Fp3.sub(t3, t4);
t4 = Fp3.add(X1, Z1);
let t5 = Fp3.add(X2, Z2);
t4 = Fp3.mul(t4, t5);
t5 = Fp3.add(t0, t2);
t4 = Fp3.sub(t4, t5);
t5 = Fp3.add(Y1, Z1);
X3 = Fp3.add(Y2, Z2);
t5 = Fp3.mul(t5, X3);
X3 = Fp3.add(t1, t2);
t5 = Fp3.sub(t5, X3);
Z3 = Fp3.mul(a, t4);
X3 = Fp3.mul(b3, t2);
Z3 = Fp3.add(X3, Z3);
X3 = Fp3.sub(t1, Z3);
Z3 = Fp3.add(t1, Z3);
Y3 = Fp3.mul(X3, Z3);
t1 = Fp3.add(t0, t0);
t1 = Fp3.add(t1, t0);
t2 = Fp3.mul(a, t2);
t4 = Fp3.mul(b3, t4);
t1 = Fp3.add(t1, t2);
t2 = Fp3.sub(t0, t2);
t2 = Fp3.mul(a, t2);
t4 = Fp3.add(t4, t2);
t0 = Fp3.mul(t1, t4);
Y3 = Fp3.add(Y3, t0);
t0 = Fp3.mul(t5, t4);
X3 = Fp3.mul(t3, X3);
X3 = Fp3.sub(X3, t0);
t0 = Fp3.mul(t3, t1);
Z3 = Fp3.mul(t5, Z3);
Z3 = Fp3.add(Z3, t0);
return new Point(X3, Y3, Z3);
}
subtract(other) {
return this.add(other.negate());
}
is0() {
return this.equals(Point.ZERO);
}
wNAF(n) {
return wnaf.wNAFCached(this, n, Point.normalizeZ);
}
/**
* Non-constant-time multiplication. Uses double-and-add algorithm.
* It's faster, but should only be used when you don't care about
* an exposed private key e.g. sig verification, which works over *public* keys.
*/
multiplyUnsafe(sc) {
aInRange("scalar", sc, _0n$4, CURVE.n);
const I = Point.ZERO;
if (sc === _0n$4)
return I;
if (sc === _1n$6)
return this;
const { endo } = CURVE;
if (!endo)
return wnaf.unsafeLadder(this, sc);
let { k1neg, k1, k2neg, k2 } = endo.splitScalar(sc);
let k1p = I;
let k2p = I;
let d = this;
while (k1 > _0n$4 || k2 > _0n$4) {
if (k1 & _1n$6)
k1p = k1p.add(d);
if (k2 & _1n$6)
k2p = k2p.add(d);
d = d.double();
k1 >>= _1n$6;
k2 >>= _1n$6;
}
if (k1neg)
k1p = k1p.negate();
if (k2neg)
k2p = k2p.negate();
k2p = new Point(Fp3.mul(k2p.px, endo.beta), k2p.py, k2p.pz);
return k1p.add(k2p);
}
/**
* Constant time multiplication.
* Uses wNAF method. Windowed method may be 10% faster,
* but takes 2x longer to generate and consumes 2x memory.
* Uses precomputes when available.
* Uses endomorphism for Koblitz curves.
* @param scalar by which the point would be multiplied
* @returns New point
*/
multiply(scalar) {
const { endo, n: N2 } = CURVE;
aInRange("scalar", scalar, _1n$6, N2);
let point, fake;
if (endo) {
const { k1neg, k1, k2neg, k2 } = endo.splitScalar(scalar);
let { p: k1p, f: f1p } = this.wNAF(k1);
let { p: k2p, f: f2p } = this.wNAF(k2);
k1p = wnaf.constTimeNegate(k1neg, k1p);
k2p = wnaf.constTimeNegate(k2neg, k2p);
k2p = new Point(Fp3.mul(k2p.px, endo.beta), k2p.py, k2p.pz);
point = k1p.add(k2p);
fake = f1p.add(f2p);
} else {
const { p, f: f2 } = this.wNAF(scalar);
point = p;
fake = f2;
}
return Point.normalizeZ([point, fake])[0];
}
/**
* Efficiently calculate `aP + bQ`. Unsafe, can expose private key, if used incorrectly.
* Not using Strauss-Shamir trick: precomputation tables are faster.
* The trick could be useful if both P and Q are not G (not in our case).
* @returns non-zero affine point
*/
multiplyAndAddUnsafe(Q, a, b) {
const G = Point.BASE;
const mul = (P, a2) => a2 === _0n$4 || a2 === _1n$6 || !P.equals(G) ? P.multiplyUnsafe(a2) : P.multiply(a2);
const sum = mul(this, a).add(mul(Q, b));
return sum.is0() ? void 0 : sum;
}
// Converts Projective point to affine (x, y) coordinates.
// Can accept precomputed Z^-1 - for example, from invertBatch.
// (x, y, z) ∋ (x=x/z, y=y/z)
toAffine(iz) {
return toAffineMemo(this, iz);
}
isTorsionFree() {
const { h: cofactor, isTorsionFree } = CURVE;
if (cofactor === _1n$6)
return true;
if (isTorsionFree)
return isTorsionFree(Point, this);
throw new Error("isTorsionFree() has not been declared for the elliptic curve");
}
clearCofactor() {
const { h: cofactor, clearCofactor } = CURVE;
if (cofactor === _1n$6)
return this;
if (clearCofactor)
return clearCofactor(Point, this);
return this.multiplyUnsafe(CURVE.h);
}
toRawBytes(isCompressed = true) {
abool("isCompressed", isCompressed);
this.assertValidity();
return toBytes2(Point, this, isCompressed);
}
toHex(isCompressed = true) {
abool("isCompressed", isCompressed);
return bytesToHex$2(this.toRawBytes(isCompressed));
}
}
Point.BASE = new Point(CURVE.Gx, CURVE.Gy, Fp3.ONE);
Point.ZERO = new Point(Fp3.ZERO, Fp3.ONE, Fp3.ZERO);
const _bits = CURVE.nBitLength;
const wnaf = wNAF(Point, CURVE.endo ? Math.ceil(_bits / 2) : _bits);
return {
CURVE,
ProjectivePoint: Point,
normPrivateKeyToScalar,
weierstrassEquation,
isWithinCurveOrder
};
}
function validateOpts(curve) {
const opts = validateBasic(curve);
validateObject(opts, {
hash: "hash",
hmac: "function",
randomBytes: "function"
}, {
bits2int: "function",
bits2int_modN: "function",
lowS: "boolean"
});
return Object.freeze({ lowS: true, ...opts });
}
function weierstrass(curveDef) {
const CURVE = validateOpts(curveDef);
const { Fp: Fp3, n: CURVE_ORDER } = CURVE;
const compressedLen = Fp3.BYTES + 1;
const uncompressedLen = 2 * Fp3.BYTES + 1;
function modN(a) {
return mod$1(a, CURVE_ORDER);
}
function invN(a) {
return invert(a, CURVE_ORDER);
}
const { ProjectivePoint: Point, normPrivateKeyToScalar, weierstrassEquation, isWithinCurveOrder } = weierstrassPoints({
...CURVE,
toBytes(_c, point, isCompressed) {
const a = point.toAffine();
const x = Fp3.toBytes(a.x);
const cat = concatBytes$2;
abool("isCompressed", isCompressed);
if (isCompressed) {
return cat(Uint8Array.from([point.hasEvenY() ? 2 : 3]), x);
} else {
return cat(Uint8Array.from([4]), x, Fp3.toBytes(a.y));
}
},
fromBytes(bytes2) {
const len = bytes2.length;
const head = bytes2[0];
const tail = bytes2.subarray(1);
if (len === compressedLen && (head === 2 || head === 3)) {
const x = bytesToNumberBE(tail);
if (!inRange(x, _1n$6, Fp3.ORDER))
throw new Error("Point is not on curve");
const y2 = weierstrassEquation(x);
let y;
try {
y = Fp3.sqrt(y2);
} catch (sqrtError) {
const suffix = sqrtError instanceof Error ? ": " + sqrtError.message : "";
throw new Error("Point is not on curve" + suffix);
}
const isYOdd = (y & _1n$6) === _1n$6;
const isHeadOdd = (head & 1) === 1;
if (isHeadOdd !== isYOdd)
y = Fp3.neg(y);
return { x, y };
} else if (len === uncompressedLen && head === 4) {
const x = Fp3.fromBytes(tail.subarray(0, Fp3.BYTES));
const y = Fp3.fromBytes(tail.subarray(Fp3.BYTES, 2 * Fp3.BYTES));
return { x, y };
} else {
throw new Error(`Point of length ${len} was invalid. Expected ${compressedLen} compressed bytes or ${uncompressedLen} uncompressed bytes`);
}
}
});
const numToNByteStr = (num) => bytesToHex$2(numberToBytesBE(num, CURVE.nByteLength));
function isBiggerThanHalfOrder(number2) {
const HALF = CURVE_ORDER >> _1n$6;
return number2 > HALF;
}
function normalizeS(s) {
return isBiggerThanHalfOrder(s) ? modN(-s) : s;
}
const slcNum = (b, from, to) => bytesToNumberBE(b.slice(from, to));
class Signature {
constructor(r, s, recovery) {
this.r = r;
this.s = s;
this.recovery = recovery;
this.assertValidity();
}
// pair (bytes of r, bytes of s)
static fromCompact(hex) {
const l = CURVE.nByteLength;
hex = ensureBytes("compactSignature", hex, l * 2);
return new Signature(slcNum(hex, 0, l), slcNum(hex, l, 2 * l));
}
// DER encoded ECDSA signature
// https://bitcoin.stackexchange.com/questions/57644/what-are-the-parts-of-a-bitcoin-transaction-input-script
static fromDER(hex) {
const { r, s } = DER.toSig(ensureBytes("DER", hex));
return new Signature(r, s);
}
assertValidity() {
aInRange("r", this.r, _1n$6, CURVE_ORDER);
aInRange("s", this.s, _1n$6, CURVE_ORDER);
}
addRecoveryBit(recovery) {
return new Signature(this.r, this.s, recovery);
}
recoverPublicKey(msgHash) {
const { r, s, recovery: rec } = this;
const h = bits2int_modN(ensureBytes("msgHash", msgHash));
if (rec == null || ![0, 1, 2, 3].includes(rec))
throw new Error("recovery id invalid");
const radj = rec === 2 || rec === 3 ? r + CURVE.n : r;
if (radj >= Fp3.ORDER)
throw new Error("recovery id 2 or 3 invalid");
const prefix = (rec & 1) === 0 ? "02" : "03";
const R2 = Point.fromHex(prefix + numToNByteStr(radj));
const ir = invN(radj);
const u1 = modN(-h * ir);
const u2 = modN(s * ir);
const Q = Point.BASE.multiplyAndAddUnsafe(R2, u1, u2);
if (!Q)
throw new Error("point at infinify");
Q.assertValidity();
return Q;
}
// Signatures should be low-s, to prevent malleability.
hasHighS() {
return isBiggerThanHalfOrder(this.s);
}
normalizeS() {
return this.hasHighS() ? new Signature(this.r, modN(-this.s), this.recovery) : this;
}
// DER-encoded
toDERRawBytes() {
return hexToBytes$3(this.toDERHex());
}
toDERHex() {
return DER.hexFromSig({ r: this.r, s: this.s });
}
// padded bytes of r, then padded bytes of s
toCompactRawBytes() {
return hexToBytes$3(this.toCompactHex());
}
toCompactHex() {
return numToNByteStr(this.r) + numToNByteStr(this.s);
}
}
const utils = {
isValidPrivateKey(privateKey) {
try {
normPrivateKeyToScalar(privateKey);
return true;
} catch (error) {
return false;
}
},
normPrivateKeyToScalar,
/**
* Produces cryptographically secure private key from random of size
* (groupLen + ceil(groupLen / 2)) with modulo bias being negligible.
*/
randomPrivateKey: () => {
const length = getMinHashLength(CURVE.n);
return mapHashToField(CURVE.randomBytes(length), CURVE.n);
},
/**
* Creates precompute table for an arbitrary EC point. Makes point "cached".
* Allows to massively speed-up `point.multiply(scalar)`.
* @returns cached point
* @example
* const fast = utils.precompute(8, ProjectivePoint.fromHex(someonesPubKey));
* fast.multiply(privKey); // much faster ECDH now
*/
precompute(windowSize = 8, point = Point.BASE) {
point._setWindowSize(windowSize);
point.multiply(BigInt(3));
return point;
}
};
function getPublicKey(privateKey, isCompressed = true) {
return Point.fromPrivateKey(privateKey).toRawBytes(isCompressed);
}
function isProbPub(item) {
const arr = isBytes(item);
const str = typeof item === "string";
const len = (arr || str) && item.length;
if (arr)
return len === compressedLen || len === uncompressedLen;
if (str)
return len === 2 * compressedLen || len === 2 * uncompressedLen;
if (item instanceof Point)
return true;