{"challengeId":"aes-sbox-gates","entry":"verifier.mjs","sha256":"c2620f7fac5e96bc46ec2416501228d71ee409694c6c03b94f2fd0f86e49c7db","scoreDirection":"minimize","scoreLabel":"gates","seedPolicy":{"mode":"fixed","testCount":256},"source":"// Frozen verifier for aes-sbox-gates. Self-contained (no imports). It interprets\n// a candidate straight-line boolean netlist that claims to compute the AES S-box\n// and returns a Verdict. It NEVER executes agent code — build() already ran in the\n// sandbox and handed us plain JSON data. This file is the challenge's PROTECTED\n// surface. Everything below is PURE INTEGER bitwise arithmetic.\n//\n// Artifact shape:\n//   {\n//     gates:   [ { op:'AND'|'OR'|'XOR'|'XNOR'|'NOT', a:<wireRef>, b:<wireRef> }, ... ],\n//     outputs: [ w0, w1, w2, w3, w4, w5, w6, w7 ]   // 8 wireRefs\n//   }\n// Wire numbering: refs 0..7 are the 8 input bits (bit k = (x >> k) & 1). Gate i\n// produces wire (8 + i). A netlist is straight-line/acyclic iff every wireRef a\n// gate (or output) reads is STRICTLY LESS than that gate's own output index — i.e.\n// it only references inputs or EARLIER gates. NOT reads only `a` (its `b` is\n// ignored but must still be a valid in-range earlier ref).\n//\n// Score = number of gates (minimize). Lower is better.\n\nconst N_IN = 8;\nconst N_OUT = 8;\nconst MAX_GATES = 200000; // generous cap; an honest SOP is a few thousand gates.\nconst OPS = new Set(['AND', 'OR', 'XOR', 'XNOR', 'NOT']);\n\n// The AES S-box, embedded as one 256-entry integer table (no derivation, no Math).\nconst SBOX = [\n  0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,\n  0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,\n  0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,\n  0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,\n  0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,\n  0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,\n  0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,\n  0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,\n  0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,\n  0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,\n  0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,\n  0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,\n  0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,\n  0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,\n  0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,\n  0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,\n];\n\nfunction gate(name, pass, detail) {\n  return { name, pass, detail };\n}\nfunction bad(name, detail) {\n  return { ok: false, score: null, gates: [gate(name, false, detail)], behavior: {}, logs: [] };\n}\n\nexport function verify(ctx) {\n  const sol = ctx && ctx.solution;\n  if (!sol || typeof sol !== 'object' || Array.isArray(sol)) {\n    return bad('structure', 'solution is not an object');\n  }\n\n  const { gates, outputs } = sol;\n\n  if (!Array.isArray(gates)) return bad('structure', 'gates must be an array');\n  if (gates.length > MAX_GATES) return bad('structure', `gates length must be <= ${MAX_GATES}`);\n  if (!Array.isArray(outputs) || outputs.length !== N_OUT) {\n    return bad('structure', `outputs must be an array of ${N_OUT} wire refs`);\n  }\n\n  // Total wire count = 8 inputs + one wire per gate.\n  const totalWires = N_IN + gates.length;\n\n  // Validate every gate: known op, integer in-range refs, and STRICTLY EARLIER refs\n  // (acyclic / straight-line). Gate i lives at wire (N_IN + i); it may read any wire\n  // index < (N_IN + i).\n  for (let i = 0; i < gates.length; i++) {\n    const g = gates[i];\n    if (!g || typeof g !== 'object' || Array.isArray(g)) {\n      return bad('structure', `gate ${i} is not an object`);\n    }\n    if (!OPS.has(g.op)) {\n      return bad('structure', `gate ${i} has unknown op ${String(g.op)}`);\n    }\n    const here = N_IN + i;\n    if (!Number.isInteger(g.a) || g.a < 0 || g.a >= here) {\n      return bad('structure', `gate ${i} input a=${String(g.a)} must be an earlier wire in [0, ${here})`);\n    }\n    // NOT only logically reads `a`, but `b` must still be a valid earlier ref so the\n    // artifact stays well-formed (no out-of-range or forward dangling field).\n    if (!Number.isInteger(g.b) || g.b < 0 || g.b >= here) {\n      return bad('structure', `gate ${i} input b=${String(g.b)} must be an earlier wire in [0, ${here})`);\n    }\n  }\n\n  // Validate output refs are in-range (any wire is a legal output, including inputs).\n  for (let k = 0; k < N_OUT; k++) {\n    const w = outputs[k];\n    if (!Number.isInteger(w) || w < 0 || w >= totalWires) {\n      return bad('structure', `output ${k} ref=${String(w)} out of range [0, ${totalWires})`);\n    }\n  }\n\n  // Functional check over ALL 256 inputs. Pure-integer bitwise evaluation.\n  const vals = new Array(totalWires);\n  for (let x = 0; x < 256; x++) {\n    // Seed input wires (bit k of x).\n    vals[0] = x & 1;\n    vals[1] = (x >> 1) & 1;\n    vals[2] = (x >> 2) & 1;\n    vals[3] = (x >> 3) & 1;\n    vals[4] = (x >> 4) & 1;\n    vals[5] = (x >> 5) & 1;\n    vals[6] = (x >> 6) & 1;\n    vals[7] = (x >> 7) & 1;\n\n    for (let i = 0; i < gates.length; i++) {\n      const g = gates[i];\n      const a = vals[g.a] & 1;\n      const b = vals[g.b] & 1;\n      let r;\n      switch (g.op) {\n        case 'AND': r = a & b; break;\n        case 'OR': r = a | b; break;\n        case 'XOR': r = a ^ b; break;\n        case 'XNOR': r = (a ^ b) ^ 1; break;\n        case 'NOT': r = a ^ 1; break;\n        default: r = 0; // unreachable: op set was validated above.\n      }\n      vals[N_IN + i] = r & 1;\n    }\n\n    let out = 0;\n    for (let k = 0; k < N_OUT; k++) out |= (vals[outputs[k]] & 1) << k;\n\n    if (out !== SBOX[x]) {\n      return {\n        ok: false,\n        score: null,\n        gates: [gate('functional', false, `input ${x}: got ${out}, want ${SBOX[x]}`)],\n        behavior: {},\n        logs: [],\n      };\n    }\n  }\n\n  const score = gates.length;\n  return {\n    ok: true,\n    score,\n    gates: [\n      gate('structure', true, `${gates.length} gates, ${totalWires} wires`),\n      gate('functional', true, 'all 256 S-box rows correct'),\n    ],\n    behavior: { gates: gates.length },\n    logs: [`gates=${gates.length} score=${score}`],\n  };\n}\n"}